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.

1442 lines
40 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. const CLSID CLSID_CEnroll =
  17. {0x43F8F289, 0x7A20, 0x11D0, {0x8F, 0x06, 0x00, 0xC0, 0x4F, 0xC2, 0x95, 0xE1}};
  18. const IID IID_IEnroll =
  19. {0xacaa7838, 0x4585, 0x11d1, {0xab, 0x57, 0x00, 0xc0, 0x4f, 0xc2, 0x95, 0xe1}};
  20. const IID IID_ICEnroll2 =
  21. {0x704ca730, 0xc90b, 0x11d1, {0x9b, 0xec, 0x00, 0xc0, 0x4f, 0xc2, 0x95, 0xe1}};
  22. const CLSID CLSID_CCertRequest =
  23. {0x98aff3f0, 0x5524, 0x11d0, {0x88, 0x12, 0x00, 0xa0, 0xc9, 0x03, 0xb8, 0x3c}};
  24. const IID IID_ICertRequest =
  25. {0x014e4840, 0x5523, 0x11d0, {0x88, 0x12, 0x00, 0xa0, 0xc9, 0x03, 0xb8, 0x3c}};
  26. WCHAR * bstrEmpty = L"";
  27. extern CCertWizApp theApp;
  28. BOOL
  29. CCryptBlob::Resize(DWORD cb)
  30. {
  31. if (cb > GetSize())
  32. {
  33. if (NULL !=
  34. (m_blob.pbData = Realloc(m_blob.pbData, cb)))
  35. {
  36. m_blob.cbData = cb;
  37. return TRUE;
  38. }
  39. return FALSE;
  40. }
  41. return TRUE;
  42. }
  43. IMPLEMENT_DYNAMIC(CCertificate, CObject)
  44. CCertificate::CCertificate()
  45. : m_CAType(CA_OFFLINE),
  46. m_KeyLength(512),
  47. m_pPendingRequest(NULL),
  48. m_RespCertContext(NULL),
  49. m_pInstalledCert(NULL),
  50. m_pKeyRingCert(NULL),
  51. m_pEnroll(NULL),
  52. m_status_code(-1),
  53. m_CreateDirectory(FALSE),
  54. m_SGCcertificat(FALSE),
  55. m_DefaultCSP(TRUE),
  56. m_DefaultProviderType(PROV_RSA_SCHANNEL)
  57. {
  58. }
  59. CCertificate::~CCertificate()
  60. {
  61. if (m_pPendingRequest != NULL)
  62. CertFreeCertificateContext(m_pPendingRequest);
  63. if (m_RespCertContext != NULL)
  64. CertFreeCertificateContext(m_RespCertContext);
  65. if (m_pInstalledCert != NULL)
  66. CertFreeCertificateContext(m_pInstalledCert);
  67. if (m_pKeyRingCert != NULL)
  68. CertFreeCertificateContext(m_pKeyRingCert);
  69. if (m_pEnroll != NULL)
  70. m_pEnroll->Release();
  71. }
  72. const TCHAR szResponseFileName[] = _T("ResponseFileName");
  73. const TCHAR szKeyRingFileName[] = _T("KeyRingFileName");
  74. const TCHAR szRequestFileName[] = _T("RequestFileName");
  75. const TCHAR szCertificateTemplate[] = _T("CertificateTemplate");
  76. const TCHAR szState[] = _T("State");
  77. const TCHAR szStateMRU[] = _T("StateMRU");
  78. const TCHAR szLocality[] = _T("Locality");
  79. const TCHAR szLocalityMRU[] = _T("LocalityMRU");
  80. const TCHAR szOrganization[] = _T("Organization");
  81. const TCHAR szOrganizationMRU[] = _T("OrganizationMRU");
  82. const TCHAR szOrganizationUnit[] = _T("OrganizationUnit");
  83. const TCHAR szOrganizationUnitMRU[] = _T("OrganizationUnitMRU");
  84. #define QUERY_NAME(x,y)\
  85. do {\
  86. if (ERROR_SUCCESS == RegQueryValueEx(hKey, (x), NULL, &dwType, NULL, &cbData))\
  87. {\
  88. ASSERT(dwType == REG_SZ);\
  89. pName = (BYTE *)(y).GetBuffer(cbData);\
  90. RegQueryValueEx(hKey, (x), NULL, &dwType, pName, &cbData);\
  91. if (pName != NULL)\
  92. {\
  93. (y).ReleaseBuffer();\
  94. pName = NULL;\
  95. }\
  96. }\
  97. } while (0)
  98. BOOL
  99. CCertificate::Init()
  100. {
  101. ASSERT(!m_MachineName.IsEmpty());
  102. ASSERT(!m_WebSiteInstanceName.IsEmpty());
  103. // get web site description from metabase, it could be empty
  104. // do not panic in case of error
  105. if (!GetServerComment(m_MachineName, m_WebSiteInstanceName, m_FriendlyName, &m_hResult))
  106. m_hResult = S_OK;
  107. m_CommonName = m_MachineName;
  108. m_CommonName.MakeLower();
  109. HKEY hKey = theApp.RegOpenKeyWizard();
  110. DWORD dwType;
  111. DWORD cbData;
  112. if (hKey != NULL)
  113. {
  114. BYTE * pName = NULL;
  115. QUERY_NAME(szRequestFileName, m_ReqFileName);
  116. QUERY_NAME(szResponseFileName, m_RespFileName);
  117. QUERY_NAME(szKeyRingFileName, m_KeyFileName);
  118. QUERY_NAME(szCertificateTemplate, m_CertificateTemplate);
  119. QUERY_NAME(szState, m_State);
  120. QUERY_NAME(szLocality, m_Locality);
  121. QUERY_NAME(szOrganization, m_Organization);
  122. QUERY_NAME(szOrganizationUnit, m_OrganizationUnit);
  123. RegCloseKey(hKey);
  124. }
  125. #ifdef _DEBUG
  126. else
  127. {
  128. TRACE(_T("Failed to open Registry key for Wizard parameters\n"));
  129. }
  130. #endif
  131. if (m_CertificateTemplate.IsEmpty())
  132. {
  133. // User didn't defined anything -- use standard name
  134. m_CertificateTemplate = wszCERTTYPE_WEBSERVER;
  135. }
  136. return TRUE;
  137. }
  138. #define SAVE_NAME(x,y)\
  139. do {\
  140. if (!(y).IsEmpty())\
  141. {\
  142. VERIFY(ERROR_SUCCESS == RegSetValueEx(hKey, (x), 0, REG_SZ, \
  143. (const BYTE *)(LPCTSTR)(y), \
  144. sizeof(TCHAR) * ((y).GetLength() + 1)));\
  145. }\
  146. } while (0)
  147. BOOL
  148. CCertificate::SaveSettings()
  149. {
  150. HKEY hKey = theApp.RegOpenKeyWizard();
  151. if (hKey != NULL)
  152. {
  153. switch (GetStatusCode())
  154. {
  155. case REQUEST_NEW_CERT:
  156. case REQUEST_RENEW_CERT:
  157. SAVE_NAME(szState, m_State);
  158. AddToMRU(szStateMRU, m_State);
  159. SAVE_NAME(szLocality, m_Locality);
  160. AddToMRU(szLocalityMRU, m_Locality);
  161. SAVE_NAME(szOrganization, m_Organization);
  162. AddToMRU(szOrganizationMRU, m_Organization);
  163. SAVE_NAME(szOrganizationUnit, m_OrganizationUnit);
  164. AddToMRU(szOrganizationUnitMRU, m_OrganizationUnit);
  165. SAVE_NAME(szRequestFileName, m_ReqFileName);
  166. break;
  167. case REQUEST_PROCESS_PENDING:
  168. SAVE_NAME(szResponseFileName, m_RespFileName);
  169. break;
  170. case REQUEST_IMPORT_KEYRING:
  171. SAVE_NAME(szKeyRingFileName, m_KeyFileName);
  172. break;
  173. default:
  174. break;
  175. }
  176. RegCloseKey(hKey);
  177. return TRUE;
  178. }
  179. #ifdef _DEBUG
  180. else
  181. {
  182. TRACE(_T("Failed to open Registry key for Wizard parameters\n"));
  183. }
  184. #endif
  185. return FALSE;
  186. }
  187. BOOL
  188. CCertificate::SetSecuritySettings()
  189. {
  190. long dwGenKeyFlags;
  191. if (SUCCEEDED(GetEnrollObject()->get_GenKeyFlags(&dwGenKeyFlags)))
  192. {
  193. dwGenKeyFlags &= 0x0000FFFF;
  194. dwGenKeyFlags |= (m_KeyLength << 16);
  195. if (m_SGCcertificat)
  196. dwGenKeyFlags |= CRYPT_SGCKEY;
  197. return (SUCCEEDED(GetEnrollObject()->put_GenKeyFlags(dwGenKeyFlags)));
  198. }
  199. return FALSE;
  200. }
  201. // defines taken from the old KeyGen utility
  202. #define MESSAGE_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----\r\n"
  203. #define MESSAGE_TRAILER "-----END NEW CERTIFICATE REQUEST-----\r\n"
  204. BOOL
  205. CCertificate::WriteRequestString(CString& request)
  206. {
  207. ASSERT(!PathIsRelative(m_ReqFileName));
  208. BOOL bRes = FALSE;
  209. try {
  210. CString strPath;
  211. strPath = m_ReqFileName;
  212. LPTSTR pPath = strPath.GetBuffer(strPath.GetLength());
  213. PathRemoveFileSpec(pPath);
  214. if (!PathIsDirectory(pPath))
  215. {
  216. if (!CreateDirectoryFromPath(strPath, NULL))
  217. {
  218. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  219. SetBodyTextID(USE_DEFAULT_CAPTION);
  220. return FALSE;
  221. }
  222. }
  223. strPath.ReleaseBuffer();
  224. HANDLE hFile = ::CreateFile(m_ReqFileName,
  225. GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  226. if (hFile != INVALID_HANDLE_VALUE)
  227. {
  228. DWORD cb = request.GetLength();
  229. char * ascii_buf = (char *)_alloca(cb);
  230. wcstombs(ascii_buf, request, cb);
  231. bRes = ::WriteFile(hFile, ascii_buf, cb, &cb, NULL);
  232. ::CloseHandle(hFile);
  233. }
  234. else
  235. {
  236. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  237. SetBodyTextID(USE_DEFAULT_CAPTION);
  238. }
  239. }
  240. catch (CFileException * e)
  241. {
  242. TCHAR szCause[255];
  243. e->GetErrorMessage(szCause, 255);
  244. TRACE(_T("Got CFileException with error: %s\n"), szCause);
  245. m_hResult = HRESULT_FROM_WIN32(e->m_lOsError);
  246. }
  247. catch (CException * e)
  248. {
  249. TCHAR szCause[255];
  250. e->GetErrorMessage(szCause, 255);
  251. TRACE(_T("Got CException with error: %s\n"), szCause);
  252. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  253. }
  254. return bRes;
  255. }
  256. #define HEADER_SERVER_ _T("Server:\t%s\r\n\r\n")
  257. #define HEADER_COMMON_NAME_ _T("Common-name:\t%s\r\n")
  258. #define HEADER_FRIENDLY_NAME_ _T("Friendly name:\t%s\r\n")
  259. #define HEADER_ORG_UNIT_ _T("Organization Unit:\t%s\r\n")
  260. #define HEADER_ORGANIZATION_ _T("Organization:\t%s\r\n")
  261. #define HEADER_LOCALITY_ _T("Locality:\t%s\r\n")
  262. #define HEADER_STATE_ _T("State:\t%s\r\n")
  263. #define HEADER_COUNTRY_ _T("Country:\t%s\r\n")
  264. static void WRITE_LINE(CString& str, TCHAR * format, CString& data)
  265. {
  266. CString buf;
  267. buf.Format(format, data);
  268. str += buf;
  269. }
  270. void
  271. CCertificate::DumpHeader(CString& str)
  272. {
  273. DumpOnlineHeader(str);
  274. }
  275. void
  276. CCertificate::DumpOnlineHeader(CString& str)
  277. {
  278. WRITE_LINE(str, HEADER_SERVER_, m_CommonName);
  279. WRITE_LINE(str, HEADER_FRIENDLY_NAME_, m_FriendlyName);
  280. WRITE_LINE(str, HEADER_ORG_UNIT_, m_OrganizationUnit);
  281. WRITE_LINE(str, HEADER_ORGANIZATION_, m_Organization);
  282. WRITE_LINE(str, HEADER_LOCALITY_, m_Locality);;
  283. WRITE_LINE(str, HEADER_STATE_, m_State);
  284. WRITE_LINE(str, HEADER_COUNTRY_, m_Country);
  285. }
  286. BOOL
  287. CCertificate::GetSelectedCertDescription(CERT_DESCRIPTION& cd)
  288. {
  289. BOOL bRes = FALSE;
  290. ASSERT(m_pSelectedCertHash != NULL);
  291. HCERTSTORE hStore = OpenMyStore(GetEnrollObject(), &m_hResult);
  292. if (hStore != NULL)
  293. {
  294. PCCERT_CONTEXT pCert = CertFindCertificateInStore(hStore,
  295. CRYPT_ASN_ENCODING,
  296. 0,
  297. CERT_FIND_HASH,
  298. m_pSelectedCertHash,
  299. NULL);
  300. if (pCert != NULL)
  301. {
  302. bRes = GetCertDescription(pCert, cd);
  303. CertFreeCertificateContext(pCert);
  304. }
  305. CertCloseStore(hStore, 0);
  306. }
  307. return bRes;
  308. }
  309. void CCertificate::CreateDN(CString& str)
  310. {
  311. str.Empty();
  312. str += _T("CN=") + m_CommonName;
  313. str += _T("\n,OU=") + m_OrganizationUnit;
  314. str += _T("\n,O=") + m_Organization;
  315. str += _T("\n,L=") + m_Locality;
  316. str += _T("\n,S=") + m_State;
  317. str += _T("\n,C=") + m_Country;
  318. }
  319. PCCERT_CONTEXT
  320. CCertificate::GetPendingRequest()
  321. {
  322. if (m_pPendingRequest == NULL)
  323. {
  324. ASSERT(!m_WebSiteInstanceName.IsEmpty());
  325. m_pPendingRequest = GetPendingDummyCert(m_WebSiteInstanceName,
  326. GetEnrollObject(), &m_hResult);
  327. }
  328. return m_pPendingRequest;
  329. }
  330. PCCERT_CONTEXT
  331. CCertificate::GetInstalledCert()
  332. {
  333. if (m_pInstalledCert == NULL)
  334. {
  335. m_pInstalledCert = ::GetInstalledCert(m_MachineName,
  336. m_WebSiteInstanceName,
  337. GetEnrollObject(),
  338. &m_hResult);
  339. }
  340. return m_pInstalledCert;
  341. }
  342. PCCERT_CONTEXT
  343. CCertificate::GetKeyRingCert()
  344. {
  345. ASSERT(!m_KeyFileName.IsEmpty());
  346. ASSERT(!m_KeyPassword.IsEmpty());
  347. if (m_pKeyRingCert == NULL)
  348. {
  349. int len = m_KeyPassword.GetLength() * 2;
  350. char * ascii_password = (char *)_alloca(len + 1);
  351. ASSERT(ascii_password != NULL);
  352. size_t n;
  353. VERIFY(-1 != (n = wcstombs(ascii_password, m_KeyPassword, len)));
  354. ascii_password[n] = '\0';
  355. m_pKeyRingCert = ::ImportKRBackupToCAPIStore(
  356. (LPTSTR)(LPCTSTR)m_KeyFileName,
  357. ascii_password,
  358. _T("MY"));
  359. if (m_pKeyRingCert == NULL)
  360. {
  361. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  362. }
  363. }
  364. return m_pKeyRingCert;
  365. }
  366. /* INTRINSA suppress=null_pointers, uninitialized */
  367. PCCERT_CONTEXT
  368. CCertificate::GetResponseCert()
  369. {
  370. if (m_RespCertContext == NULL)
  371. {
  372. ASSERT(!m_RespFileName.IsEmpty());
  373. m_RespCertContext = GetCertContextFromPKCS7File(
  374. m_RespFileName,
  375. &GetPendingRequest()->pCertInfo->SubjectPublicKeyInfo,
  376. &m_hResult);
  377. ASSERT(SUCCEEDED(m_hResult));
  378. }
  379. return m_RespCertContext;
  380. }
  381. BOOL
  382. CCertificate::GetResponseCertDescription(CERT_DESCRIPTION& cd)
  383. {
  384. CERT_DESCRIPTION cdReq;
  385. if (GetCertDescription(GetResponseCert(), cd))
  386. {
  387. if (GetCertDescription(GetPendingRequest(), cdReq))
  388. {
  389. cd.m_FriendlyName = cdReq.m_FriendlyName;
  390. }
  391. return TRUE;
  392. }
  393. return FALSE;
  394. }
  395. /*------------------------------------------------------------------------------
  396. IsResponseInstalled
  397. Function checks if certificate from the response file
  398. m_RespFileName was istalled to some server. If possible,
  399. it returns name of this server in str.
  400. Returns FALSE if certificate is not found in MY store or
  401. if this store cannot be opened
  402. */
  403. BOOL
  404. CCertificate::IsResponseInstalled(
  405. CString& str // return server instance name (not yet implemented)
  406. )
  407. {
  408. BOOL bRes = FALSE;
  409. // get cert context from response file
  410. PCCERT_CONTEXT pContext = GetCertContextFromPKCS7File(
  411. m_RespFileName, NULL, &m_hResult);
  412. if (pContext != NULL)
  413. {
  414. HCERTSTORE hStore = OpenMyStore(GetEnrollObject(), &m_hResult);
  415. if (hStore != NULL)
  416. {
  417. PCCERT_CONTEXT pCert = NULL;
  418. while (NULL != (pCert = CertEnumCertificatesInStore(hStore, pCert)))
  419. {
  420. // do not include installed cert to the list
  421. if (CertCompareCertificate(X509_ASN_ENCODING,
  422. pContext->pCertInfo, pCert->pCertInfo))
  423. {
  424. bRes = TRUE;
  425. // Try to find, where is was installed
  426. break;
  427. }
  428. }
  429. if (pCert != NULL)
  430. CertFreeCertificateContext(pCert);
  431. }
  432. }
  433. return bRes;
  434. }
  435. BOOL
  436. CCertificate::FindInstanceNameForResponse(CString& str)
  437. {
  438. BOOL bRes = FALSE;
  439. // get cert context from response file
  440. PCCERT_CONTEXT pContext = GetCertContextFromPKCS7File(
  441. m_RespFileName, NULL, &m_hResult);
  442. if (pContext != NULL)
  443. {
  444. // find dummy cert in REQUEST store that has public key
  445. // the same as in this context
  446. PCCERT_CONTEXT pReq = GetReqCertByKey(GetEnrollObject(),
  447. &pContext->pCertInfo->SubjectPublicKeyInfo, &m_hResult);
  448. if (pReq != NULL)
  449. {
  450. // get friendly name prop from this dummy cert
  451. if (!GetFriendlyName(pReq, str, &m_hResult))
  452. {
  453. // get instance name prop from this dummy cert
  454. DWORD cb;
  455. BYTE * prop;
  456. if ( CertGetCertificateContextProperty(pReq, CERTWIZ_INSTANCE_NAME_PROP_ID, NULL, &cb)
  457. && (NULL != (prop = (BYTE *)_alloca(cb)))
  458. && CertGetCertificateContextProperty(pReq, CERTWIZ_INSTANCE_NAME_PROP_ID, prop, &cb)
  459. )
  460. {
  461. // decode this instance name property
  462. DWORD cbData = 0;
  463. BYTE * data = NULL;
  464. if ( CryptDecodeObject(CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING,
  465. prop, cb, 0, NULL, &cbData)
  466. && (NULL != (data = (BYTE *)_alloca(cbData)))
  467. && CryptDecodeObject(CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING,
  468. prop, cb, 0, data, &cbData)
  469. )
  470. {
  471. CERT_NAME_VALUE * p = (CERT_NAME_VALUE *)data;
  472. CString strInstanceName = (LPCTSTR)p->Value.pbData;
  473. // now try to get comment from this server
  474. if (GetServerComment(m_MachineName, strInstanceName, str, &m_hResult))
  475. {
  476. if (str.IsEmpty())
  477. {
  478. // generate something like [Web Site #n]
  479. str.LoadString(IDS_WEB_SITE_N);
  480. int len = strInstanceName.GetLength();
  481. for (int i = len - 1, count = 0; i >= 0; i--, count++)
  482. {
  483. if (!_istdigit(strInstanceName.GetAt(i)))
  484. break;
  485. }
  486. ASSERT(count < len);
  487. AfxFormatString1(str, IDS_WEB_SITE_N, strInstanceName.Right(count));
  488. }
  489. }
  490. m_hResult = S_OK;
  491. bRes = TRUE;
  492. }
  493. }
  494. }
  495. CertFreeCertificateContext(pReq);
  496. }
  497. else
  498. {
  499. // probably this request was deleted from the request store
  500. }
  501. CertFreeCertificateContext(pContext);
  502. }
  503. return bRes;
  504. }
  505. IEnroll *
  506. CCertificate::GetEnrollObject()
  507. {
  508. if (m_pEnroll == NULL)
  509. {
  510. m_hResult = CoCreateInstance(CLSID_CEnroll,
  511. NULL,
  512. CLSCTX_INPROC_SERVER,
  513. IID_IEnroll,
  514. (void **)&m_pEnroll);
  515. // now we need to change defaults for this
  516. // object to LOCAL_MACHINE
  517. if (m_pEnroll != NULL)
  518. {
  519. long dwFlags;
  520. VERIFY(SUCCEEDED(m_pEnroll->get_MyStoreFlags(&dwFlags)));
  521. dwFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK;
  522. dwFlags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
  523. // following call will change Request store flags also
  524. VERIFY(SUCCEEDED(m_pEnroll->put_MyStoreFlags(dwFlags)));
  525. VERIFY(SUCCEEDED(m_pEnroll->get_GenKeyFlags(&dwFlags)));
  526. dwFlags |= CRYPT_EXPORTABLE;
  527. VERIFY(SUCCEEDED(m_pEnroll->put_GenKeyFlags(dwFlags)));
  528. VERIFY(SUCCEEDED(m_pEnroll->put_KeySpec(AT_KEYEXCHANGE)));
  529. VERIFY(SUCCEEDED(m_pEnroll->put_ProviderType(m_DefaultProviderType)));
  530. VERIFY(SUCCEEDED(m_pEnroll->put_DeleteRequestCert(TRUE)));
  531. }
  532. }
  533. ASSERT(m_pEnroll != NULL);
  534. return m_pEnroll;
  535. }
  536. BOOL
  537. CCertificate::HasInstalledCert()
  538. {
  539. BOOL bResult = FALSE;
  540. CMetaKey key(m_MachineName,
  541. METADATA_PERMISSION_READ,
  542. METADATA_MASTER_ROOT_HANDLE,
  543. m_WebSiteInstanceName);
  544. if (key.Succeeded())
  545. {
  546. CString store_name;
  547. CBlob blob;
  548. if ( S_OK == key.QueryValue(MD_SSL_CERT_HASH, blob)
  549. && S_OK == key.QueryValue(MD_SSL_CERT_STORE_NAME, store_name)
  550. )
  551. {
  552. bResult = TRUE;
  553. }
  554. }
  555. return bResult;
  556. }
  557. HRESULT
  558. CCertificate::UninstallCert()
  559. {
  560. CMetaKey key(m_MachineName,
  561. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  562. METADATA_MASTER_ROOT_HANDLE,
  563. m_WebSiteInstanceName);
  564. if (key.Succeeded())
  565. {
  566. CString store_name;
  567. key.QueryValue(MD_SSL_CERT_STORE_NAME, store_name);
  568. if (SUCCEEDED(key.DeleteValue(MD_SSL_CERT_HASH)))
  569. key.DeleteValue(MD_SSL_CERT_STORE_NAME);
  570. }
  571. return m_hResult = key.QueryResult();
  572. }
  573. BOOL CCertificate::WriteRequestBody()
  574. {
  575. ASSERT(!m_ReqFileName.IsEmpty());
  576. HRESULT hr;
  577. BOOL bRes = FALSE;
  578. CString strDN;
  579. CreateDN(strDN);
  580. ASSERT(!strDN.IsEmpty());
  581. CString strUsage(szOID_PKIX_KP_SERVER_AUTH);
  582. CCryptBlobIMalloc request;
  583. GetEnrollObject()->put_ProviderType(m_DefaultCSP ?
  584. m_DefaultProviderType : m_CustomProviderType);
  585. if (!m_DefaultCSP)
  586. {
  587. GetEnrollObject()->put_ProviderNameWStr((LPTSTR)(LPCTSTR)m_CspName);
  588. GetEnrollObject()->put_KeySpec(AT_SIGNATURE);
  589. }
  590. if (SUCCEEDED(hr = GetEnrollObject()->createPKCS10WStr((LPTSTR)(LPCTSTR)strDN,
  591. (LPTSTR)(LPCTSTR)strUsage,
  592. request)))
  593. {
  594. // BASE64 encode pkcs 10
  595. DWORD err, cch;
  596. char * psz;
  597. if ( (err = Base64EncodeA(request.GetData(), request.GetSize(), NULL, &cch)) == ERROR_SUCCESS
  598. && (psz = (char *)_alloca(cch)) != NULL
  599. && (err = Base64EncodeA(request.GetData(), request.GetSize(), psz, &cch)) == ERROR_SUCCESS
  600. )
  601. {
  602. HANDLE hFile = ::CreateFile(m_ReqFileName,
  603. GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  604. if (hFile == NULL)
  605. return FALSE;
  606. DWORD written;
  607. ::SetFilePointer(hFile, 0, NULL, FILE_END);
  608. ::WriteFile(hFile, MESSAGE_HEADER, sizeof(MESSAGE_HEADER) - 1, &written, NULL);
  609. ::WriteFile(hFile, psz, cch, &written, NULL);
  610. ::WriteFile(hFile, MESSAGE_TRAILER, sizeof(MESSAGE_TRAILER) - 1, &written, NULL);
  611. ::CloseHandle(hFile);
  612. // get back request from encoded data
  613. PCERT_REQUEST_INFO req_info;
  614. VERIFY(GetRequestInfoFromPKCS10(request, &req_info, &m_hResult));
  615. // find dummy cert put to request store by createPKCS10 call
  616. HCERTSTORE hStore = OpenRequestStore(GetEnrollObject(), &m_hResult);
  617. if (hStore != NULL)
  618. {
  619. PCCERT_CONTEXT pDummyCert = CertFindCertificateInStore(hStore,
  620. CRYPT_ASN_ENCODING,
  621. 0,
  622. CERT_FIND_PUBLIC_KEY,
  623. (void *)&req_info->SubjectPublicKeyInfo,
  624. NULL);
  625. if (pDummyCert != NULL)
  626. {
  627. // now we need to attach web server instance name to this cert
  628. // encode string into data blob
  629. CRYPT_DATA_BLOB name;
  630. CERT_NAME_VALUE name_value;
  631. name_value.dwValueType = CERT_RDN_BMP_STRING;
  632. name_value.Value.cbData = 0;
  633. name_value.Value.pbData = (LPBYTE)(LPCTSTR)m_WebSiteInstanceName;
  634. {
  635. if ( !CryptEncodeObject(CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING,
  636. &name_value, NULL, &name.cbData)
  637. || (name.pbData = (BYTE *)_alloca(name.cbData)) == NULL
  638. || !CryptEncodeObject(CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING,
  639. &name_value, name.pbData, &name.cbData)
  640. )
  641. {
  642. ASSERT(FALSE);
  643. }
  644. VERIFY(bRes = CertSetCertificateContextProperty(pDummyCert,
  645. CERTWIZ_INSTANCE_NAME_PROP_ID, 0, &name));
  646. }
  647. // put friendly name to dummy cert -- we will reuse it later
  648. m_FriendlyName.ReleaseBuffer();
  649. AttachFriendlyName(pDummyCert, m_FriendlyName, &m_hResult);
  650. // we also need to put some flag to show what we are waiting for:
  651. // new sertificate or renewing certificate
  652. CRYPT_DATA_BLOB flag;
  653. if ( !CryptEncodeObject(CRYPT_ASN_ENCODING, X509_INTEGER,
  654. &m_status_code, NULL, &flag.cbData)
  655. || (flag.pbData = (BYTE *)_alloca(flag.cbData)) == NULL
  656. || !CryptEncodeObject(CRYPT_ASN_ENCODING, X509_INTEGER,
  657. &m_status_code, flag.pbData, &flag.cbData)
  658. )
  659. {
  660. ASSERT(FALSE);
  661. }
  662. VERIFY(bRes = CertSetCertificateContextProperty(pDummyCert,
  663. CERTWIZ_REQUEST_FLAG_PROP_ID, 0, &flag));
  664. CertFreeCertificateContext(pDummyCert);
  665. }
  666. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  667. }
  668. LocalFree(req_info);
  669. }
  670. bRes = TRUE;
  671. }
  672. return bRes;
  673. }
  674. BOOL
  675. CCertificate::InstallResponseCert()
  676. {
  677. BOOL bRes = FALSE;
  678. CCryptBlobLocal blobRequestText;
  679. // Get all our data attached to dummy cert
  680. GetFriendlyName(GetPendingRequest(), m_FriendlyName, &m_hResult);
  681. ASSERT(!m_FriendlyName.IsEmpty());
  682. GetBlobProperty(GetPendingRequest(),
  683. CERTWIZ_REQUEST_TEXT_PROP_ID, blobRequestText, &m_hResult);
  684. ASSERT(blobRequestText.GetSize() != 0);
  685. CCryptBlobLocal hash_blob;
  686. if (::GetHashProperty(GetResponseCert(), hash_blob, &m_hResult))
  687. {
  688. if (SUCCEEDED(m_hResult = GetEnrollObject()->acceptFilePKCS7WStr(
  689. (LPTSTR)(LPCTSTR)m_RespFileName))
  690. && InstallCertByHash(hash_blob, m_MachineName, m_WebSiteInstanceName,
  691. GetEnrollObject(), &m_hResult)
  692. )
  693. {
  694. // reattach friendly name and request text to installed cert
  695. m_FriendlyName.ReleaseBuffer();
  696. AttachFriendlyName(GetInstalledCert(), m_FriendlyName, &m_hResult);
  697. bRes = CertSetCertificateContextProperty(GetInstalledCert(),
  698. CERTWIZ_REQUEST_TEXT_PROP_ID, 0, blobRequestText);
  699. }
  700. }
  701. if (!bRes)
  702. {
  703. SetBodyTextID(USE_DEFAULT_CAPTION);
  704. }
  705. return bRes;
  706. }
  707. // We don't have initial request for KeyRing certificate, therefore we will
  708. // not be able to renew this certificate
  709. //
  710. BOOL
  711. CCertificate::InstallKeyRingCert()
  712. {
  713. BOOL bRes = FALSE;
  714. CCryptBlobLocal hash_blob;
  715. if (::GetHashProperty(GetKeyRingCert(), hash_blob, &m_hResult))
  716. {
  717. HRESULT hr;
  718. CString name;
  719. ::GetFriendlyName(GetKeyRingCert(), name, &hr);
  720. if (CRYPT_E_NOT_FOUND == hr || name.IsEmpty())
  721. {
  722. CERT_DESCRIPTION desc;
  723. if (GetCertDescription(GetKeyRingCert(), desc))
  724. bRes = AttachFriendlyName(GetKeyRingCert(), desc.m_CommonName, &hr);
  725. }
  726. ASSERT(bRes);
  727. bRes = InstallCertByHash(hash_blob, m_MachineName, m_WebSiteInstanceName,
  728. GetEnrollObject(), &m_hResult);
  729. }
  730. if (!bRes)
  731. {
  732. SetBodyTextID(USE_DEFAULT_CAPTION);
  733. }
  734. return bRes;
  735. }
  736. // Instead of renewal we create new certificate based on parameters
  737. // from the current one. After creation we install this certificate in place
  738. // of current one and deleting the old one from store. Even if IIS has an
  739. // opened SSL connection it should get a notification and update the certificate
  740. // data.
  741. //
  742. BOOL
  743. CCertificate::SubmitRenewalRequest()
  744. {
  745. BOOL bRes = LoadRenewalData();
  746. if (bRes)
  747. {
  748. PCCERT_CONTEXT pCurrent = GetInstalledCert();
  749. m_pInstalledCert = NULL;
  750. if (bRes = SubmitRequest())
  751. {
  752. CertDeleteCertificateFromStore(pCurrent);
  753. }
  754. }
  755. return bRes;
  756. }
  757. BOOL CCertificate::SubmitRequest()
  758. {
  759. ASSERT(!m_ConfigCA.IsEmpty());
  760. BOOL bRes = FALSE;
  761. ICertRequest * pRequest = NULL;
  762. if (SUCCEEDED(m_hResult = CoCreateInstance(CLSID_CCertRequest, NULL,
  763. CLSCTX_INPROC_SERVER, IID_ICertRequest, (void **)&pRequest)))
  764. {
  765. CString strDN;
  766. CreateDN(strDN);
  767. BSTR request;
  768. if (SUCCEEDED(m_hResult = CreateRequest_Base64(
  769. (BSTR)(LPCTSTR)strDN,
  770. GetEnrollObject(),
  771. m_DefaultCSP ? NULL : (LPTSTR)(LPCTSTR)m_CspName,
  772. m_DefaultCSP ? m_DefaultProviderType : m_CustomProviderType,
  773. &request)))
  774. {
  775. ASSERT(pRequest != NULL);
  776. CString attrib;
  777. GetCertificateTemplate(attrib);
  778. LONG disp;
  779. m_hResult = pRequest->Submit(CR_IN_BASE64 | CR_IN_PKCS10,
  780. request,
  781. (BSTR)(LPCTSTR)attrib,
  782. (LPTSTR)(LPCTSTR)m_ConfigCA,
  783. &disp);
  784. #ifdef _DEBUG
  785. if (FAILED(m_hResult))
  786. TRACE(_T("Submit request returned HRESULT %x; Disposition %x\n"),
  787. m_hResult, disp);
  788. #endif
  789. if (SUCCEEDED(m_hResult))
  790. {
  791. if (disp == CR_DISP_ISSUED)
  792. {
  793. BSTR bstrOutCert = NULL;
  794. if (SUCCEEDED(m_hResult =
  795. pRequest->GetCertificate(CR_OUT_BASE64 /*| CR_OUT_CHAIN */, &bstrOutCert)))
  796. {
  797. CRYPT_DATA_BLOB blob;
  798. blob.cbData = SysStringByteLen(bstrOutCert);
  799. blob.pbData = (BYTE *)bstrOutCert;
  800. m_hResult = GetEnrollObject()->acceptPKCS7Blob(&blob);
  801. if (SUCCEEDED(m_hResult))
  802. {
  803. PCCERT_CONTEXT pContext = GetCertContextFromPKCS7(blob.pbData, blob.cbData,
  804. NULL, &m_hResult);
  805. ASSERT(pContext != NULL);
  806. if (pContext != NULL)
  807. {
  808. BYTE HashBuffer[40]; // give it some extra size
  809. DWORD dwHashSize = sizeof(HashBuffer);
  810. if (CertGetCertificateContextProperty(pContext,
  811. CERT_SHA1_HASH_PROP_ID,
  812. (VOID *) HashBuffer,
  813. &dwHashSize))
  814. {
  815. CRYPT_HASH_BLOB hash_blob = {dwHashSize, HashBuffer};
  816. if (!(bRes = InstallHashToMetabase(&hash_blob,
  817. m_MachineName,
  818. m_WebSiteInstanceName,
  819. &m_hResult)))
  820. {
  821. SetBodyTextID(IDS_CERT_INSTALLATION_FAILURE);
  822. }
  823. }
  824. CertFreeCertificateContext(pContext);
  825. }
  826. // now put extra properties to the installed cert
  827. if (NULL != (pContext = GetInstalledCert()))
  828. {
  829. if (!(bRes = AttachFriendlyName(pContext, m_FriendlyName, &m_hResult)))
  830. {
  831. SetBodyTextID(IDS_CERT_INSTALLATION_FAILURE);
  832. }
  833. }
  834. }
  835. SysFreeString(bstrOutCert);
  836. }
  837. }
  838. else
  839. {
  840. switch (disp)
  841. {
  842. case CR_DISP_INCOMPLETE:
  843. case CR_DISP_ERROR:
  844. case CR_DISP_DENIED:
  845. case CR_DISP_ISSUED_OUT_OF_BAND:
  846. case CR_DISP_UNDER_SUBMISSION:
  847. {
  848. BSTR bstr;
  849. if (SUCCEEDED(pRequest->GetDispositionMessage(&bstr)))
  850. {
  851. SetBodyTextString(CString(bstr));
  852. SysFreeString(bstr);
  853. }
  854. m_hResult = !S_OK;
  855. }
  856. break;
  857. default:
  858. SetBodyTextID(IDS_INTERNAL_ERROR);
  859. break;
  860. }
  861. }
  862. }
  863. else // !SUCCEEDED
  864. {
  865. // clear out any error IDs and strings
  866. // we will use default processing of m_hResult
  867. SetBodyTextID(USE_DEFAULT_CAPTION);
  868. }
  869. SysFreeString(request);
  870. }
  871. pRequest->Release();
  872. }
  873. return bRes;
  874. }
  875. BOOL
  876. CCertificate::PrepareRequestString(CString& request_text, CCryptBlob& request_blob)
  877. {
  878. CString strDN;
  879. TCHAR szUsage[] = _T(szOID_PKIX_KP_SERVER_AUTH);
  880. if (m_status_code == REQUEST_RENEW_CERT)
  881. {
  882. if ( FALSE == LoadRenewalData()
  883. || FALSE == SetSecuritySettings()
  884. )
  885. return FALSE;
  886. }
  887. CreateDN(strDN);
  888. ASSERT(!strDN.IsEmpty());
  889. GetEnrollObject()->put_ProviderType(m_DefaultCSP ?
  890. m_DefaultProviderType : m_CustomProviderType);
  891. if (!m_DefaultCSP)
  892. {
  893. GetEnrollObject()->put_ProviderNameWStr((LPTSTR)(LPCTSTR)m_CspName);
  894. // We are supporting only these two types of CSP, it is pretty safe to
  895. // have just two options, because we are using the same two types when
  896. // we are populating CSP selection list.
  897. if (m_CustomProviderType == PROV_DH_SCHANNEL)
  898. GetEnrollObject()->put_KeySpec(AT_SIGNATURE);
  899. else if (m_CustomProviderType == PROV_RSA_SCHANNEL)
  900. GetEnrollObject()->put_KeySpec(AT_KEYEXCHANGE);
  901. }
  902. if (FAILED(m_hResult = GetEnrollObject()->createPKCS10WStr((LPTSTR)(LPCTSTR)strDN,
  903. szUsage, request_blob))
  904. )
  905. {
  906. SetBodyTextID(USE_DEFAULT_CAPTION);
  907. return FALSE;
  908. }
  909. // BASE64 encode pkcs 10
  910. DWORD err, cch;
  911. char * psz;
  912. if ( ERROR_SUCCESS != (err = Base64EncodeA(request_blob.GetData(), request_blob.GetSize(), NULL, &cch))
  913. || NULL == (psz = (char *)_alloca(cch+1))
  914. || ERROR_SUCCESS != (err = Base64EncodeA(request_blob.GetData(), request_blob.GetSize(), psz, &cch))
  915. )
  916. {
  917. return FALSE;
  918. }
  919. psz[cch] = '\0';
  920. request_text = MESSAGE_HEADER;
  921. request_text += psz;
  922. request_text += MESSAGE_TRAILER;
  923. return TRUE;
  924. }
  925. BOOL
  926. CCertificate::PrepareRequest()
  927. {
  928. BOOL bRes = FALSE;
  929. CString request_text;
  930. CCryptBlobIMalloc request_blob;
  931. if (PrepareRequestString(request_text, request_blob))
  932. {
  933. if (WriteRequestString(request_text))
  934. {
  935. CCryptBlobLocal name_blob, request_store_blob, status_blob;
  936. // prepare data we want to attach to dummy request
  937. if ( EncodeString(m_WebSiteInstanceName, name_blob, &m_hResult)
  938. && EncodeInteger(m_status_code, status_blob, &m_hResult)
  939. )
  940. {
  941. // get back request from encoded data
  942. PCERT_REQUEST_INFO pReqInfo;
  943. bRes = GetRequestInfoFromPKCS10(request_blob, &pReqInfo, &m_hResult);
  944. if (bRes)
  945. {
  946. // find dummy cert put to request store by createPKCS10 call
  947. HCERTSTORE hStore = OpenRequestStore(GetEnrollObject(), &m_hResult);
  948. if (hStore != NULL)
  949. {
  950. PCCERT_CONTEXT pDummyCert = CertFindCertificateInStore(hStore,
  951. CRYPT_ASN_ENCODING,
  952. 0,
  953. CERT_FIND_PUBLIC_KEY,
  954. (void *)&pReqInfo->SubjectPublicKeyInfo,
  955. NULL);
  956. if (pDummyCert != NULL)
  957. {
  958. if ( CertSetCertificateContextProperty(pDummyCert,
  959. CERTWIZ_INSTANCE_NAME_PROP_ID, 0, name_blob)
  960. && CertSetCertificateContextProperty(pDummyCert,
  961. CERTWIZ_REQUEST_FLAG_PROP_ID, 0, status_blob)
  962. // put friendly name to dummy cert -- we will reuse it later
  963. && AttachFriendlyName(pDummyCert, m_FriendlyName, &m_hResult)
  964. )
  965. {
  966. bRes = TRUE;
  967. // put certificate text to the clipboard
  968. if (OpenClipboard(GetFocus()))
  969. {
  970. size_t len = request_text.GetLength() + 1;
  971. HANDLE hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
  972. LPSTR pMem = (LPSTR)GlobalLock(hMem);
  973. if (pMem != NULL)
  974. {
  975. wcstombs(pMem, request_text, len);
  976. GlobalUnlock(hMem);
  977. SetClipboardData(CF_TEXT, hMem);
  978. }
  979. CloseClipboard();
  980. }
  981. }
  982. else
  983. {
  984. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  985. }
  986. CertFreeCertificateContext(pDummyCert);
  987. }
  988. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  989. }
  990. LocalFree(pReqInfo);
  991. }
  992. }
  993. }
  994. }
  995. if (!bRes)
  996. SetBodyTextID(USE_DEFAULT_CAPTION);
  997. return bRes;
  998. }
  999. BOOL CCertificate::LoadRenewalData()
  1000. {
  1001. // we need to obtain data from the installed cert
  1002. CERT_DESCRIPTION desc;
  1003. ASSERT(GetInstalledCert() != NULL);
  1004. BOOL res = FALSE;
  1005. if (GetCertDescription(GetInstalledCert(), desc))
  1006. {
  1007. m_CommonName = desc.m_CommonName;
  1008. m_FriendlyName = desc.m_FriendlyName;
  1009. m_Country = desc.m_Country;
  1010. m_State = desc.m_State;
  1011. m_Locality = desc.m_Locality;
  1012. m_Organization = desc.m_Organization;
  1013. m_OrganizationUnit = desc.m_OrganizationUnit;
  1014. DWORD len = CertGetPublicKeyLength(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1015. &GetInstalledCert()->pCertInfo->SubjectPublicKeyInfo);
  1016. if (len == 0)
  1017. {
  1018. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  1019. goto ErrorExit;
  1020. }
  1021. m_KeyLength = len;
  1022. BYTE pbData[1024];
  1023. CRYPT_KEY_PROV_INFO * pProvInfo = (CRYPT_KEY_PROV_INFO *)pbData;
  1024. DWORD dwData = 1000;
  1025. if (!CertGetCertificateContextProperty(GetInstalledCert(),
  1026. CERT_KEY_PROV_INFO_PROP_ID, pProvInfo, &dwData))
  1027. {
  1028. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  1029. goto ErrorExit;
  1030. }
  1031. if (pProvInfo->dwProvType != m_DefaultProviderType)
  1032. {
  1033. m_DefaultCSP = FALSE;
  1034. m_CustomProviderType = pProvInfo->dwProvType;
  1035. m_CspName = pProvInfo->pwszProvName;
  1036. }
  1037. CArray<LPCSTR, LPCSTR> uses;
  1038. uses.Add(szOID_SERVER_GATED_CRYPTO);
  1039. uses.Add(szOID_SGC_NETSCAPE);
  1040. m_SGCcertificat = ContainsKeyUsageProperty(GetInstalledCert(), uses, &m_hResult);
  1041. res = TRUE;
  1042. }
  1043. ErrorExit:
  1044. return res;
  1045. }
  1046. #if 0
  1047. BOOL
  1048. CCertificate::WriteRenewalRequest()
  1049. {
  1050. BOOL bRes = FALSE;
  1051. if (GetInstalledCert() != NULL)
  1052. {
  1053. BSTR bstrRequest;
  1054. if ( SUCCEEDED(m_hResult = GetEnrollObject()->put_RenewalCertificate(GetInstalledCert()))
  1055. && SUCCEEDED(m_hResult = CreateRequest_Base64(bstrEmpty,
  1056. GetEnrollObject(),
  1057. m_DefaultCSP ? NULL : (LPTSTR)(LPCTSTR)m_CspName,
  1058. m_DefaultCSP ? m_DefaultProviderType : m_CustomProviderType,
  1059. &bstrRequest))
  1060. )
  1061. {
  1062. CString str = MESSAGE_HEADER;
  1063. str += bstrRequest;
  1064. str += MESSAGE_TRAILER;
  1065. if (WriteRequestString(str))
  1066. {
  1067. CCryptBlobLocal name_blob, status_blob;
  1068. CCryptBlobIMalloc request_blob;
  1069. request_blob.Set(SysStringLen(bstrRequest), (BYTE *)bstrRequest);
  1070. // prepare data we want to attach to dummy request
  1071. if ( EncodeString(m_WebSiteInstanceName, name_blob, &m_hResult)
  1072. && EncodeInteger(m_status_code, status_blob, &m_hResult)
  1073. )
  1074. {
  1075. // get back request from encoded data
  1076. PCERT_REQUEST_INFO req_info;
  1077. if (GetRequestInfoFromPKCS10(request_blob, &req_info, &m_hResult))
  1078. {
  1079. // find dummy cert put to request store by createPKCS10 call
  1080. HCERTSTORE hStore = OpenRequestStore(GetEnrollObject(), &m_hResult);
  1081. if (hStore != NULL)
  1082. {
  1083. PCCERT_CONTEXT pDummyCert = CertFindCertificateInStore(hStore,
  1084. CRYPT_ASN_ENCODING,
  1085. 0,
  1086. CERT_FIND_PUBLIC_KEY,
  1087. (void *)&req_info->SubjectPublicKeyInfo,
  1088. NULL);
  1089. if (pDummyCert != NULL)
  1090. {
  1091. if ( CertSetCertificateContextProperty(pDummyCert,
  1092. CERTWIZ_INSTANCE_NAME_PROP_ID, 0, name_blob)
  1093. && CertSetCertificateContextProperty(pDummyCert,
  1094. CERTWIZ_REQUEST_FLAG_PROP_ID, 0, status_blob)
  1095. // put friendly name to dummy cert -- we will reuse it later
  1096. && AttachFriendlyName(pDummyCert, m_FriendlyName, &m_hResult)
  1097. )
  1098. {
  1099. bRes = TRUE;
  1100. }
  1101. else
  1102. {
  1103. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  1104. }
  1105. CertFreeCertificateContext(pDummyCert);
  1106. }
  1107. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  1108. }
  1109. LocalFree(req_info);
  1110. }
  1111. }
  1112. }
  1113. }
  1114. }
  1115. return bRes;
  1116. }
  1117. #endif
  1118. CCertDescList::~CCertDescList()
  1119. {
  1120. POSITION pos = GetHeadPosition();
  1121. while (pos != NULL)
  1122. {
  1123. CERT_DESCRIPTION * pDesc = GetNext(pos);
  1124. delete pDesc;
  1125. }
  1126. }
  1127. BOOL
  1128. CCertificate::GetCertDescription(PCCERT_CONTEXT pCert,
  1129. CERT_DESCRIPTION& desc)
  1130. {
  1131. BOOL bRes = FALSE;
  1132. DWORD cb;
  1133. UINT i, j;
  1134. CERT_NAME_INFO * pNameInfo;
  1135. if (pCert == NULL)
  1136. goto ErrExit;
  1137. if ( !CryptDecodeObject(X509_ASN_ENCODING, X509_UNICODE_NAME,
  1138. pCert->pCertInfo->Subject.pbData,
  1139. pCert->pCertInfo->Subject.cbData,
  1140. 0, NULL, &cb)
  1141. || NULL == (pNameInfo = (CERT_NAME_INFO *)_alloca(cb))
  1142. || !CryptDecodeObject(X509_ASN_ENCODING, X509_UNICODE_NAME,
  1143. pCert->pCertInfo->Subject.pbData,
  1144. pCert->pCertInfo->Subject.cbData,
  1145. 0,
  1146. pNameInfo, &cb)
  1147. )
  1148. {
  1149. goto ErrExit;
  1150. }
  1151. for (i = 0; i < pNameInfo->cRDN; i++)
  1152. {
  1153. CERT_RDN rdn = pNameInfo->rgRDN[i];
  1154. for (j = 0; j < rdn.cRDNAttr; j++)
  1155. {
  1156. CERT_RDN_ATTR attr = rdn.rgRDNAttr[j];
  1157. if (strcmp(attr.pszObjId, szOID_COMMON_NAME) == 0)
  1158. {
  1159. FormatRdnAttr(desc.m_CommonName, attr.dwValueType, attr.Value);
  1160. }
  1161. else if (strcmp(attr.pszObjId, szOID_COUNTRY_NAME) == 0)
  1162. {
  1163. FormatRdnAttr(desc.m_Country, attr.dwValueType, attr.Value);
  1164. }
  1165. else if (strcmp(attr.pszObjId, szOID_LOCALITY_NAME) == 0)
  1166. {
  1167. FormatRdnAttr(desc.m_Locality, attr.dwValueType, attr.Value);
  1168. }
  1169. else if (strcmp(attr.pszObjId, szOID_STATE_OR_PROVINCE_NAME) == 0)
  1170. {
  1171. FormatRdnAttr(desc.m_State, attr.dwValueType, attr.Value);
  1172. }
  1173. else if (strcmp(attr.pszObjId, szOID_ORGANIZATION_NAME) == 0)
  1174. {
  1175. FormatRdnAttr(desc.m_Organization, attr.dwValueType, attr.Value);
  1176. }
  1177. else if (strcmp(attr.pszObjId, szOID_ORGANIZATIONAL_UNIT_NAME) == 0)
  1178. {
  1179. FormatRdnAttr(desc.m_OrganizationUnit, attr.dwValueType, attr.Value);
  1180. }
  1181. }
  1182. }
  1183. // issued to
  1184. if (!GetNameString(pCert, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG,
  1185. desc.m_CAName, &m_hResult))
  1186. goto ErrExit;
  1187. // expiration date
  1188. if (!FormatDateString(desc.m_ExpirationDate, pCert->pCertInfo->NotAfter, FALSE, FALSE))
  1189. {
  1190. goto ErrExit;
  1191. }
  1192. // purpose
  1193. if (!FormatEnhancedKeyUsageString(desc.m_Usage, pCert, FALSE, FALSE, &m_hResult))
  1194. {
  1195. // According to local experts, we should also use certs without this property set
  1196. ASSERT(FALSE);
  1197. //goto ErrExit;
  1198. }
  1199. // friendly name
  1200. if (!GetFriendlyName(pCert, desc.m_FriendlyName, &m_hResult))
  1201. {
  1202. desc.m_FriendlyName.LoadString(IDS_FRIENDLYNAME_NONE);
  1203. }
  1204. bRes = TRUE;
  1205. ErrExit:
  1206. return bRes;
  1207. }
  1208. int
  1209. CCertificate::MyStoreCertCount()
  1210. {
  1211. int count = 0;
  1212. HCERTSTORE hStore = OpenMyStore(GetEnrollObject(), &m_hResult);
  1213. if (hStore != NULL)
  1214. {
  1215. PCCERT_CONTEXT pCert = NULL;
  1216. CArray<LPCSTR, LPCSTR> uses;
  1217. uses.Add(szOID_PKIX_KP_SERVER_AUTH);
  1218. uses.Add(szOID_SERVER_GATED_CRYPTO);
  1219. uses.Add(szOID_SGC_NETSCAPE);
  1220. while (NULL != (pCert = CertEnumCertificatesInStore(hStore, pCert)))
  1221. {
  1222. // do not include installed cert to the list
  1223. if ( GetInstalledCert() != NULL
  1224. && CertCompareCertificate(X509_ASN_ENCODING,
  1225. GetInstalledCert()->pCertInfo, pCert->pCertInfo)
  1226. )
  1227. continue;
  1228. if (!ContainsKeyUsageProperty(pCert, uses, &m_hResult))
  1229. {
  1230. continue;
  1231. }
  1232. count++;
  1233. }
  1234. if (pCert != NULL)
  1235. CertFreeCertificateContext(pCert);
  1236. VERIFY(CertCloseStore(hStore, 0));
  1237. }
  1238. return count;
  1239. }
  1240. BOOL
  1241. CCertificate::GetCertDescList(CCertDescList& list)
  1242. {
  1243. ASSERT(list.GetCount() == 0);
  1244. BOOL bRes = FALSE;
  1245. // we are looking to MY store only
  1246. HCERTSTORE hStore = OpenMyStore(GetEnrollObject(), &m_hResult);
  1247. if (hStore != NULL)
  1248. {
  1249. PCCERT_CONTEXT pCert = NULL;
  1250. // do not include certs with improper usage
  1251. CArray<LPCSTR, LPCSTR> uses;
  1252. uses.Add(szOID_PKIX_KP_SERVER_AUTH);
  1253. uses.Add(szOID_SERVER_GATED_CRYPTO);
  1254. uses.Add(szOID_SGC_NETSCAPE);
  1255. while (NULL != (pCert = CertEnumCertificatesInStore(hStore, pCert)))
  1256. {
  1257. // do not include installed cert to the list
  1258. if ( GetInstalledCert() != NULL
  1259. && CertCompareCertificate(X509_ASN_ENCODING,
  1260. GetInstalledCert()->pCertInfo, pCert->pCertInfo)
  1261. )
  1262. continue;
  1263. if (!ContainsKeyUsageProperty(pCert, uses, &m_hResult))
  1264. {
  1265. if (SUCCEEDED(m_hResult) || m_hResult == CRYPT_E_NOT_FOUND)
  1266. continue;
  1267. else
  1268. goto ErrExit;
  1269. }
  1270. CERT_DESCRIPTION * pDesc = new CERT_DESCRIPTION;
  1271. pDesc->m_hash_length = CERT_HASH_LENGTH;
  1272. if (!GetCertDescription(pCert, *pDesc))
  1273. {
  1274. delete pDesc;
  1275. if (m_hResult == CRYPT_E_NOT_FOUND)
  1276. continue;
  1277. goto ErrExit;
  1278. }
  1279. if (!CertGetCertificateContextProperty(pCert,
  1280. CERT_SHA1_HASH_PROP_ID,
  1281. (VOID *)pDesc->m_hash,
  1282. &pDesc->m_hash_length))
  1283. {
  1284. delete pDesc;
  1285. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  1286. goto ErrExit;
  1287. }
  1288. list.AddTail(pDesc);
  1289. }
  1290. bRes = TRUE;
  1291. ErrExit:
  1292. if (pCert != NULL)
  1293. CertFreeCertificateContext(pCert);
  1294. VERIFY(CertCloseStore(hStore, 0));
  1295. }
  1296. return bRes;
  1297. }
  1298. BOOL
  1299. CCertificate::ReplaceInstalled()
  1300. {
  1301. // Current cert will be left in the store for next use
  1302. // Selected cert will be installed instead
  1303. return InstallSelectedCert();
  1304. }
  1305. BOOL
  1306. CCertificate::CancelRequest()
  1307. {
  1308. // we are just removing dummy cert from the REQUEST store
  1309. if (NULL != GetPendingRequest())
  1310. {
  1311. BOOL bRes = CertDeleteCertificateFromStore(GetPendingRequest());
  1312. if (!bRes)
  1313. {
  1314. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  1315. SetBodyTextID(USE_DEFAULT_CAPTION);
  1316. }
  1317. else
  1318. m_pPendingRequest = NULL;
  1319. return bRes;
  1320. }
  1321. return FALSE;
  1322. }
  1323. BOOL
  1324. CCertificate::InstallSelectedCert()
  1325. {
  1326. BOOL bRes = FALSE;
  1327. HRESULT hr;
  1328. // local authorities required that cert should have some
  1329. // friendly name. We will put common name when friendly name is not available
  1330. HCERTSTORE hStore = OpenMyStore(GetEnrollObject(), &hr);
  1331. if (hStore != NULL)
  1332. {
  1333. PCCERT_CONTEXT pCert = CertFindCertificateInStore(hStore,
  1334. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1335. 0, CERT_FIND_HASH,
  1336. (LPVOID)m_pSelectedCertHash,
  1337. NULL);
  1338. if (pCert != NULL)
  1339. {
  1340. CString name;
  1341. ::GetFriendlyName(pCert, name, &hr);
  1342. if (CRYPT_E_NOT_FOUND == hr || name.IsEmpty())
  1343. {
  1344. CERT_DESCRIPTION desc;
  1345. if (GetCertDescription(pCert, desc))
  1346. bRes = AttachFriendlyName(pCert, desc.m_CommonName, &hr);
  1347. }
  1348. }
  1349. VERIFY(CertCloseStore(hStore, 0));
  1350. }
  1351. ASSERT(bRes);
  1352. // we are just rewriting current settings
  1353. // current cert will be left in MY store
  1354. bRes = ::InstallCertByHash(m_pSelectedCertHash,
  1355. m_MachineName,
  1356. m_WebSiteInstanceName,
  1357. GetEnrollObject(),
  1358. &m_hResult);
  1359. if (!bRes)
  1360. {
  1361. SetBodyTextID(USE_DEFAULT_CAPTION);
  1362. }
  1363. return bRes;
  1364. }