Leaked source code of windows server 2003
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.

2410 lines
72 KiB

  1. #include "stdafx.h"
  2. #include "CertObj.h"
  3. #include "common.h"
  4. #include "certutil.h"
  5. #include "base64.h"
  6. #include <strsafe.h>
  7. //////////////////////////////////////////////////////////////////
  8. CString ReturnGoodMetabasePath(CString csInstanceName)
  9. {
  10. CString key_path_lm = _T("");
  11. CString key_path = _T("");
  12. // csInstanceName will come in looking like
  13. // w3svc/1
  14. // or /lm/w3svc/1
  15. //
  16. // we want to it to go out as /lm/w3svc/1
  17. key_path_lm = SZ_MBN_SEP_STR SZ_MBN_MACHINE SZ_MBN_SEP_STR;// SZ_MBN_WEB SZ_MBN_SEP_STR;
  18. if (csInstanceName.GetLength() >= 4)
  19. {
  20. if (csInstanceName.Left(4) == key_path_lm)
  21. {
  22. key_path = csInstanceName;
  23. }
  24. else
  25. {
  26. key_path_lm = SZ_MBN_MACHINE SZ_MBN_SEP_STR;
  27. if (csInstanceName.Left(3) == key_path_lm)
  28. {
  29. key_path = csInstanceName;
  30. }
  31. else
  32. {
  33. key_path = key_path_lm;
  34. key_path += csInstanceName;
  35. }
  36. }
  37. }
  38. else
  39. {
  40. key_path = key_path_lm;
  41. key_path += csInstanceName;
  42. }
  43. return key_path;
  44. }
  45. //
  46. // will come in as /W3SVC/1
  47. //
  48. // need to make sure to remove from these nodes
  49. //[/W3SVC/1/ROOT]
  50. //[/W3SVC/1/ROOT/Printers]
  51. //
  52. HRESULT ShutdownSSL(CString& server_name)
  53. {
  54. CComAuthInfo auth;
  55. CString str = ReturnGoodMetabasePath(server_name);
  56. str += _T("/root");
  57. CMetaKey key(&auth, str, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE);
  58. DWORD dwSslAccess;
  59. if (!key.Succeeded())
  60. {
  61. return key.QueryResult();
  62. }
  63. if (SUCCEEDED(key.QueryValue(MD_SSL_ACCESS_PERM, dwSslAccess)) && dwSslAccess > 0)
  64. {
  65. key.SetValue(MD_SSL_ACCESS_PERM, 0);
  66. }
  67. // Now we need to remove SSL setting from any virtual directory below
  68. CError err;
  69. CStringListEx data_paths;
  70. DWORD dwMDIdentifier, dwMDAttributes, dwMDUserType,dwMDDataType;
  71. VERIFY(CMetaKey::GetMDFieldDef(MD_SSL_ACCESS_PERM, dwMDIdentifier, dwMDAttributes, dwMDUserType,dwMDDataType));
  72. err = key.GetDataPaths( data_paths,dwMDIdentifier,dwMDDataType);
  73. if (err.Succeeded() && !data_paths.empty())
  74. {
  75. CStringListEx::iterator it = data_paths.begin();
  76. while (it != data_paths.end())
  77. {
  78. CString& str2 = (*it++);
  79. if (SUCCEEDED(key.QueryValue(MD_SSL_ACCESS_PERM, dwSslAccess, NULL, str2)) && dwSslAccess > 0)
  80. {
  81. key.SetValue(MD_SSL_ACCESS_PERM, 0, NULL, str2);
  82. }
  83. }
  84. }
  85. return key.QueryResult();
  86. }
  87. BOOL
  88. GetKeyUsageProperty(PCCERT_CONTEXT pCertContext,
  89. CERT_ENHKEY_USAGE ** pKeyUsage,
  90. BOOL fPropertiesOnly,
  91. HRESULT * phRes)
  92. {
  93. DWORD cb = 0;
  94. BOOL bRes = FALSE;
  95. if (!CertGetEnhancedKeyUsage(pCertContext,
  96. fPropertiesOnly ? CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG : 0,
  97. NULL,
  98. &cb))
  99. {
  100. *phRes = HRESULT_FROM_WIN32(GetLastError());
  101. goto ErrExit;
  102. }
  103. if (NULL == (*pKeyUsage = (CERT_ENHKEY_USAGE *)malloc(cb)))
  104. {
  105. *phRes = E_OUTOFMEMORY;
  106. goto ErrExit;
  107. }
  108. if (!CertGetEnhancedKeyUsage (pCertContext,
  109. fPropertiesOnly ? CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG : 0,
  110. *pKeyUsage,
  111. &cb))
  112. {
  113. free(*pKeyUsage);*pKeyUsage = NULL;
  114. *phRes = HRESULT_FROM_WIN32(GetLastError());
  115. goto ErrExit;
  116. }
  117. *phRes = S_OK;
  118. bRes = TRUE;
  119. ErrExit:
  120. return bRes;
  121. }
  122. // Return:
  123. // 0 = The CertContext does not have a EnhancedKeyUsage (EKU) field
  124. // 1 = The CertContext has EnhancedKeyUsage (EKU) and contains the uses we want.
  125. // This is also returned when The UsageIdentifier that depics "all uses" is true
  126. // 2 = The CertContext has EnhancedKeyUsage (EKU) but does NOT contain the uses we want.
  127. // This is also returned when The UsageIdentifier that depics "no uses" is true
  128. INT ContainsKeyUsageProperty(PCCERT_CONTEXT pCertContext,LPCSTR rgbpszUsageArray[],DWORD dwUsageArrayCount,HRESULT * phRes)
  129. {
  130. // Default it with "No EnhancedKeyUsage (EKU) Exist"
  131. INT iReturn = 0;
  132. CERT_ENHKEY_USAGE * pKeyUsage = NULL;
  133. if ( dwUsageArrayCount > 0
  134. && GetKeyUsageProperty(pCertContext, &pKeyUsage, FALSE, phRes)
  135. )
  136. {
  137. if (pKeyUsage->cUsageIdentifier == 0)
  138. {
  139. /*
  140. But in MSDN article about SR
  141. (see: ms-help://MS.MSDNQTR.2002APR.1033/security/security/certgetenhancedkeyusage.htm)
  142. In Windows Me and Windows 2000 and later, if the cUsageIdentifier member is zero (0),
  143. the certificate might be valid for ALL uses or the certificate might have no valid uses.
  144. The return from a call to GetLastError can be used to determine whether the certificate
  145. is good for all uses or for none. If GetLastError returns CRYPT_E_NOT_FOUND, the certificate
  146. is good for all uses. If it returns zero (0), the certificate has no valid uses.
  147. */
  148. // Default it with "has EnhancedKeyUsage (EKU), but doesn't have what we want"
  149. iReturn = 2;
  150. if (GetLastError() == CRYPT_E_NOT_FOUND)
  151. {
  152. // All uses!
  153. iReturn = 1;
  154. }
  155. }
  156. else
  157. {
  158. // Default it with "has EnhancedKeyUsage (EKU), but doesn't have what we want"
  159. iReturn = 2;
  160. for (DWORD i = 0; i < pKeyUsage->cUsageIdentifier; i++)
  161. {
  162. // Our friends from CAPI made this property ASCII even for
  163. // UNICODE program
  164. for (DWORD j = 0; j < dwUsageArrayCount; j++)
  165. {
  166. if (strstr(pKeyUsage->rgpszUsageIdentifier[i], rgbpszUsageArray[j]) != NULL)
  167. {
  168. iReturn = 1;
  169. break;
  170. }
  171. }
  172. }
  173. }
  174. free(pKeyUsage);
  175. }
  176. return iReturn;
  177. }
  178. BOOL CanIISUseThisCertForServerAuth(PCCERT_CONTEXT pCC)
  179. {
  180. BOOL bReturn = FALSE;
  181. HRESULT hr = E_FAIL;
  182. if (!pCC)
  183. {
  184. return FALSE;
  185. }
  186. LPCSTR rgbpszUsageArray[3];
  187. SecureZeroMemory( &rgbpszUsageArray, sizeof(rgbpszUsageArray) );
  188. rgbpszUsageArray[0] = szOID_PKIX_KP_SERVER_AUTH;
  189. rgbpszUsageArray[1] = szOID_SERVER_GATED_CRYPTO;
  190. rgbpszUsageArray[2] = szOID_SGC_NETSCAPE;
  191. DWORD dwCount=sizeof(rgbpszUsageArray)/sizeof(rgbpszUsageArray[0]);
  192. if (pCC)
  193. {
  194. INT iEnhancedKeyUsage = ContainsKeyUsageProperty(pCC,rgbpszUsageArray,dwCount,&hr);
  195. switch (iEnhancedKeyUsage)
  196. {
  197. case 0:
  198. // BUG:683489:remove check for basic constraint "subjecttype=ca"
  199. // Per bug 683489, accept it
  200. bReturn = TRUE;
  201. /*
  202. IISDebugOutput(_T("CanIISUseThisCertForServerAuth:Line=%d:No Server_Auth\r\n"),__LINE__);
  203. // check other stuff
  204. if (DID_NOT_FIND_CONSTRAINT == CheckCertConstraints(pCC) || FOUND_CONSTRAINT == CheckCertConstraints(pCC))
  205. {
  206. // it's okay, add it to the list
  207. // and can be used as server auth.
  208. bReturn = TRUE;
  209. }
  210. else
  211. {
  212. IISDebugOutput(_T("CanIISUseThisCertForServerAuth:Line=%d:Contains Constraints\r\n"),__LINE__);
  213. bReturn = FALSE;
  214. }
  215. */
  216. break;
  217. case 1:
  218. // yes!
  219. bReturn = TRUE;
  220. break;
  221. case 2:
  222. // no!
  223. bReturn = FALSE;
  224. break;
  225. default:
  226. break;
  227. }
  228. }
  229. return bReturn;
  230. }
  231. /*
  232. -----Original Message-----
  233. From: Helle Vu (SPECTOR)
  234. Sent: Friday, April 27, 2001 6:02 PM
  235. To: Aaron Lee; Trevor Freeman
  236. Cc: Sergei Antonov
  237. Subject: RE: bug 31010
  238. Perfect timing, I was just about to send you an update on this:
  239. I talked to Trevor about this, and he suggested the best thing to do for IIS would be the following (Trevor, please double-check I got this right):
  240. If there is an EKU, and it has serverauth, display it in the list to pick web server certs from
  241. If no EKU, look at basic constraints:
  242. * If we do not have basic constraints, do display it in the list to pick web server certs from
  243. * 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)
  244. * If we do have basic constraints with SubectType !=CA, do display it in the list to pick web server certs from
  245. */
  246. /*
  247. ===== Opened by kshenoy on 11/13/2000 02:26PM =====
  248. Add Existing certificate option in "Web Server Certificate Request wizard" should not list CA certificates in the filter
  249. but only End entity certificates with "Server Authentication" EKU
  250. Since CA certificates by default have all the EKUs the filter will list CA certificates apart from
  251. end entity certificates with "Server Auth" EKU.
  252. In order to check if a given certificate is a CA or end entity you can look at the Basic Constraints
  253. extension of the certificate if present. This will be present in CA certificates and set to SubjectType=CA.
  254. If present in end entity certificates it will be set to "ServerAuth"
  255. */
  256. int CheckCertConstraints(PCCERT_CONTEXT pCC)
  257. {
  258. PCERT_EXTENSION pCExt;
  259. LPCSTR pszObjId;
  260. DWORD i;
  261. CERT_BASIC_CONSTRAINTS_INFO *pConstraints=NULL;
  262. CERT_BASIC_CONSTRAINTS2_INFO *p2Constraints=NULL;
  263. DWORD ConstraintSize=0;
  264. int ReturnValue = FAILURE;
  265. BOOL Using2=FALSE;
  266. void* ConstraintBlob=NULL;
  267. pszObjId = szOID_BASIC_CONSTRAINTS;
  268. pCExt = CertFindExtension(pszObjId,pCC->pCertInfo->cExtension,pCC->pCertInfo->rgExtension);
  269. if (pCExt == NULL)
  270. {
  271. pszObjId = szOID_BASIC_CONSTRAINTS2;
  272. pCExt = CertFindExtension(pszObjId,pCC->pCertInfo->cExtension,pCC->pCertInfo->rgExtension);
  273. Using2=TRUE;
  274. }
  275. if (pCExt == NULL)
  276. {
  277. IISDebugOutput(_T("CheckCertConstraints:Line=%d:DID_NOT_FIND_CONSTRAINT\r\n"),__LINE__);
  278. ReturnValue = DID_NOT_FIND_CONSTRAINT;
  279. goto CheckCertConstraints_Exit;
  280. }
  281. // Decode extension
  282. if (!CryptDecodeObject(X509_ASN_ENCODING,pCExt->pszObjId,pCExt->Value.pbData,pCExt->Value.cbData,0,NULL,&ConstraintSize))
  283. {
  284. IISDebugOutput(_T("CheckCertConstraints:Line=%d:FAIL\r\n"),__LINE__);
  285. goto CheckCertConstraints_Exit;
  286. }
  287. ConstraintBlob = malloc(ConstraintSize);
  288. if (ConstraintBlob == NULL)
  289. {
  290. IISDebugOutput(_T("CheckCertConstraints:Line=%d:FAIL\r\n"),__LINE__);
  291. goto CheckCertConstraints_Exit;
  292. }
  293. if (!CryptDecodeObject(X509_ASN_ENCODING,pCExt->pszObjId,pCExt->Value.pbData,pCExt->Value.cbData,0,(void*)ConstraintBlob,&ConstraintSize))
  294. {
  295. IISDebugOutput(_T("CheckCertConstraints:Line=%d:FAIL\r\n"),__LINE__);
  296. goto CheckCertConstraints_Exit;
  297. }
  298. if (Using2)
  299. {
  300. p2Constraints=(CERT_BASIC_CONSTRAINTS2_INFO*)ConstraintBlob;
  301. if (!p2Constraints->fCA)
  302. {
  303. // there is a constraint, and it's not a CA
  304. ReturnValue = FOUND_CONSTRAINT;
  305. IISDebugOutput(_T("CheckCertConstraints:Line=%d:FOUND_CONSTRAINT:there is a constraint, and it's not a CA\r\n"),__LINE__);
  306. }
  307. else
  308. {
  309. // This is a CA. CA cannot be used as a 'server auth'
  310. ReturnValue = FOUND_CONSTRAINT_BUT_THIS_IS_A_CA_OR_ITS_NOT_AN_END_ENTITY;
  311. IISDebugOutput(_T("CheckCertConstraints:Line=%d:FOUND_CONSTRAINT:This is a CA. CA cannot be used as a 'server auth'\r\n"),__LINE__);
  312. }
  313. }
  314. else
  315. {
  316. pConstraints=(CERT_BASIC_CONSTRAINTS_INFO*)ConstraintBlob;
  317. if (((pConstraints->SubjectType.cbData * 8) - pConstraints->SubjectType.cUnusedBits) >= 2)
  318. {
  319. if ((*pConstraints->SubjectType.pbData) & CERT_END_ENTITY_SUBJECT_FLAG)
  320. {
  321. // there is a valid constraint
  322. ReturnValue = FOUND_CONSTRAINT;
  323. IISDebugOutput(_T("CheckCertConstraints:Line=%d:FOUND_CONSTRAINT:there is a valid constraint\r\n"),__LINE__);
  324. }
  325. else
  326. {
  327. // this is not an 'end entity' so hey -- we can't use it.
  328. ReturnValue = FOUND_CONSTRAINT_BUT_THIS_IS_A_CA_OR_ITS_NOT_AN_END_ENTITY;
  329. IISDebugOutput(_T("CheckCertConstraints:Line=%d:this is not an 'end entity' so hey -- we can't use it\r\n"),__LINE__);
  330. }
  331. }
  332. }
  333. CheckCertConstraints_Exit:
  334. if (ConstraintBlob){free(ConstraintBlob);}
  335. return (ReturnValue);
  336. }
  337. BOOL AddChainToStore(HCERTSTORE hCertStore,PCCERT_CONTEXT pCertContext,DWORD cStores,HCERTSTORE * rghStores,BOOL fDontAddRootCert,CERT_TRUST_STATUS * pChainTrustStatus)
  338. {
  339. DWORD i;
  340. CERT_CHAIN_ENGINE_CONFIG CertChainEngineConfig;
  341. HCERTCHAINENGINE hCertChainEngine = NULL;
  342. PCCERT_CHAIN_CONTEXT pCertChainContext = NULL;
  343. CERT_CHAIN_PARA CertChainPara;
  344. BOOL fRet = TRUE;
  345. PCCERT_CONTEXT pTempCertContext = NULL;
  346. //
  347. // create a new chain engine, then build the chain
  348. //
  349. memset(&CertChainEngineConfig, 0, sizeof(CertChainEngineConfig));
  350. CertChainEngineConfig.cbSize = sizeof(CertChainEngineConfig);
  351. CertChainEngineConfig.cAdditionalStore = cStores;
  352. CertChainEngineConfig.rghAdditionalStore = rghStores;
  353. CertChainEngineConfig.dwFlags = CERT_CHAIN_USE_LOCAL_MACHINE_STORE;
  354. if (!CertCreateCertificateChainEngine(&CertChainEngineConfig, &hCertChainEngine))
  355. {
  356. goto AddChainToStore_Error;
  357. }
  358. memset(&CertChainPara, 0, sizeof(CertChainPara));
  359. CertChainPara.cbSize = sizeof(CertChainPara);
  360. if (!CertGetCertificateChain(hCertChainEngine,pCertContext,NULL,NULL,&CertChainPara,0,NULL,&pCertChainContext))
  361. {
  362. goto AddChainToStore_Error;
  363. }
  364. //
  365. // make sure there is atleast 1 simple chain
  366. //
  367. if (pCertChainContext->cChain != 0)
  368. {
  369. i = 0;
  370. while (i < pCertChainContext->rgpChain[0]->cElement)
  371. {
  372. //
  373. // if we are supposed to skip the root cert,
  374. // and we are on the root cert, then continue
  375. //
  376. if (fDontAddRootCert && (pCertChainContext->rgpChain[0]->rgpElement[i]->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED))
  377. {
  378. i++;
  379. continue;
  380. }
  381. CertAddCertificateContextToStore(hCertStore,pCertChainContext->rgpChain[0]->rgpElement[i]->pCertContext,CERT_STORE_ADD_REPLACE_EXISTING,&pTempCertContext);
  382. //
  383. // remove any private key property the certcontext may have on it.
  384. //
  385. if (pTempCertContext)
  386. {
  387. CertSetCertificateContextProperty(pTempCertContext, CERT_KEY_PROV_INFO_PROP_ID, 0, NULL);
  388. CertFreeCertificateContext(pTempCertContext);
  389. }
  390. i++;
  391. }
  392. }
  393. else
  394. {
  395. goto AddChainToStore_Error;
  396. }
  397. //
  398. // if the caller wants the status, then set it
  399. //
  400. if (pChainTrustStatus != NULL)
  401. {
  402. pChainTrustStatus->dwErrorStatus = pCertChainContext->TrustStatus.dwErrorStatus;
  403. pChainTrustStatus->dwInfoStatus = pCertChainContext->TrustStatus.dwInfoStatus;
  404. }
  405. AddChainToStore_Exit:
  406. if (pCertChainContext != NULL)
  407. {
  408. CertFreeCertificateChain(pCertChainContext);
  409. }
  410. if (hCertChainEngine != NULL)
  411. {
  412. CertFreeCertificateChainEngine(hCertChainEngine);
  413. }
  414. return fRet;
  415. AddChainToStore_Error:
  416. fRet = FALSE;
  417. goto AddChainToStore_Exit;
  418. }
  419. // This function is borrowed from trustapi.cpp
  420. BOOL TrustIsCertificateSelfSigned(PCCERT_CONTEXT pContext,DWORD dwEncoding, DWORD dwFlags)
  421. {
  422. if (!(pContext) || (dwFlags != 0))
  423. {
  424. SetLastError(ERROR_INVALID_PARAMETER);
  425. return(FALSE);
  426. }
  427. if (!(CertCompareCertificateName(dwEncoding,&pContext->pCertInfo->Issuer,&pContext->pCertInfo->Subject)))
  428. {
  429. return(FALSE);
  430. }
  431. DWORD dwFlag;
  432. dwFlag = CERT_STORE_SIGNATURE_FLAG;
  433. if (!(CertVerifySubjectCertificateContext(pContext, pContext, &dwFlag)) ||
  434. (dwFlag & CERT_STORE_SIGNATURE_FLAG))
  435. {
  436. return(FALSE);
  437. }
  438. return(TRUE);
  439. }
  440. HRESULT UninstallCert(CString csInstanceName)
  441. {
  442. CComAuthInfo auth;
  443. CString key_path = ReturnGoodMetabasePath(csInstanceName);
  444. CMetaKey key(&auth, key_path, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE);
  445. if (key.Succeeded())
  446. {
  447. CString store_name;
  448. key.QueryValue(MD_SSL_CERT_STORE_NAME, store_name);
  449. if (SUCCEEDED(key.DeleteValue(MD_SSL_CERT_HASH)))
  450. {
  451. key.DeleteValue(MD_SSL_CERT_STORE_NAME);
  452. }
  453. }
  454. return key.QueryResult();
  455. }
  456. CERT_CONTEXT * GetInstalledCert(HRESULT * phResult, CString csKeyPath)
  457. {
  458. // ATLASSERT(GetEnroll() != NULL);
  459. ATLASSERT(phResult != NULL);
  460. CERT_CONTEXT * pCert = NULL;
  461. *phResult = S_OK;
  462. CComAuthInfo auth;
  463. CString key_path = ReturnGoodMetabasePath(csKeyPath);
  464. CMetaKey key(&auth, key_path, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE);
  465. if (key.Succeeded())
  466. {
  467. CString store_name;
  468. CBlob hash;
  469. if (SUCCEEDED(*phResult = key.QueryValue(MD_SSL_CERT_STORE_NAME, store_name)) &&
  470. SUCCEEDED(*phResult = key.QueryValue(MD_SSL_CERT_HASH, hash)))
  471. {
  472. // Open MY store. We assume that store type and flags
  473. // cannot be changed between installation and unistallation
  474. // of the sertificate.
  475. HCERTSTORE hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,NULL,CERT_SYSTEM_STORE_LOCAL_MACHINE,store_name);
  476. ASSERT(hStore != NULL);
  477. if (hStore != NULL)
  478. {
  479. // Now we need to find cert by hash
  480. CRYPT_HASH_BLOB crypt_hash;
  481. crypt_hash.cbData = hash.GetSize();
  482. crypt_hash.pbData = hash.GetData();
  483. pCert = (CERT_CONTEXT *)CertFindCertificateInStore(hStore,X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,0,CERT_FIND_HASH,(LPVOID)&crypt_hash,NULL);
  484. if (pCert == NULL)
  485. {
  486. *phResult = HRESULT_FROM_WIN32(GetLastError());
  487. }
  488. VERIFY(CertCloseStore(hStore, 0));
  489. }
  490. else
  491. {
  492. *phResult = HRESULT_FROM_WIN32(GetLastError());
  493. }
  494. }
  495. }
  496. else
  497. {
  498. *phResult = key.QueryResult();
  499. }
  500. return pCert;
  501. }
  502. CERT_CONTEXT * GetInstalledCert(HRESULT * phResult,DWORD cbHashBlob, char * pHashBlob)
  503. {
  504. ATLASSERT(phResult != NULL);
  505. CERT_CONTEXT * pCert = NULL;
  506. *phResult = S_OK;
  507. CString store_name = _T("MY");
  508. HCERTSTORE hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,NULL,CERT_SYSTEM_STORE_LOCAL_MACHINE,store_name);
  509. ASSERT(hStore != NULL);
  510. if (hStore != NULL)
  511. {
  512. // Now we need to find cert by hash
  513. CRYPT_HASH_BLOB crypt_hash;
  514. crypt_hash.cbData = cbHashBlob;
  515. crypt_hash.pbData = (BYTE *) pHashBlob;
  516. pCert = (CERT_CONTEXT *)CertFindCertificateInStore(hStore,X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,0,CERT_FIND_HASH,(LPVOID)&crypt_hash,NULL);
  517. if (pCert == NULL)
  518. {
  519. *phResult = HRESULT_FROM_WIN32(GetLastError());
  520. }
  521. VERIFY(CertCloseStore(hStore, 0));
  522. }
  523. else
  524. {
  525. *phResult = HRESULT_FROM_WIN32(GetLastError());
  526. }
  527. return pCert;
  528. }
  529. /*
  530. InstallHashToMetabase
  531. Function writes hash array to metabase. After that IIS
  532. could use certificate with that hash from MY store.
  533. Function expects server_name in format lm\w3svc\<number>,
  534. i.e. from root node down to virtual server
  535. */
  536. BOOL InstallHashToMetabase(CRYPT_HASH_BLOB * pHash,BSTR InstanceName,HRESULT * phResult)
  537. {
  538. BOOL bRes = FALSE;
  539. CComAuthInfo auth;
  540. CString key_path = ReturnGoodMetabasePath(InstanceName);
  541. CMetaKey key(&auth, key_path, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE);
  542. if (key.Succeeded())
  543. {
  544. CBlob blob;
  545. blob.SetValue(pHash->cbData, pHash->pbData, TRUE);
  546. bRes = SUCCEEDED(*phResult = key.SetValue(MD_SSL_CERT_HASH, blob))
  547. && SUCCEEDED(*phResult = key.SetValue(MD_SSL_CERT_STORE_NAME, CString(L"MY")));
  548. }
  549. else
  550. {
  551. *phResult = key.QueryResult();
  552. }
  553. return bRes;
  554. }
  555. HRESULT HereIsBinaryGimmieVtArray(DWORD cbBinaryBufferSize,char *pbBinaryBuffer,VARIANT * lpVarDestObject,BOOL bReturnBinaryAsVT_VARIANT)
  556. {
  557. HRESULT hr = S_OK;
  558. SAFEARRAY *aList = NULL;
  559. SAFEARRAYBOUND aBound;
  560. CHAR HUGEP *pArray = NULL;
  561. aBound.lLbound = 0;
  562. aBound.cElements = cbBinaryBufferSize;
  563. if (bReturnBinaryAsVT_VARIANT)
  564. {
  565. aList = SafeArrayCreate( VT_VARIANT, 1, &aBound );
  566. }
  567. else
  568. {
  569. aList = SafeArrayCreate( VT_UI1, 1, &aBound );
  570. }
  571. aList = SafeArrayCreate( VT_UI1, 1, &aBound );
  572. if ( aList == NULL )
  573. {
  574. hr = E_OUTOFMEMORY;
  575. goto HereIsBinaryGimmieVtArray_Exit;
  576. }
  577. hr = SafeArrayAccessData( aList, (void HUGEP * FAR *) &pArray );
  578. if (FAILED(hr))
  579. {
  580. goto HereIsBinaryGimmieVtArray_Exit;
  581. }
  582. memcpy( pArray, pbBinaryBuffer, aBound.cElements );
  583. SafeArrayUnaccessData( aList );
  584. if (bReturnBinaryAsVT_VARIANT)
  585. {
  586. V_VT(lpVarDestObject) = VT_ARRAY | VT_VARIANT;
  587. }
  588. else
  589. {
  590. V_VT(lpVarDestObject) = VT_ARRAY | VT_UI1;
  591. }
  592. V_ARRAY(lpVarDestObject) = aList;
  593. return hr;
  594. HereIsBinaryGimmieVtArray_Exit:
  595. if (aList)
  596. {SafeArrayDestroy( aList );}
  597. return hr;
  598. }
  599. HRESULT
  600. HereIsVtArrayGimmieBinary(
  601. VARIANT * lpVarSrcObject,
  602. DWORD * cbBinaryBufferSize,
  603. char **pbBinaryBuffer,
  604. BOOL bReturnBinaryAsVT_VARIANT
  605. )
  606. {
  607. HRESULT hr = S_OK;
  608. LONG dwSLBound = 0;
  609. LONG dwSUBound = 0;
  610. CHAR HUGEP *pArray = NULL;
  611. if (NULL == cbBinaryBufferSize || NULL == pbBinaryBuffer)
  612. {
  613. hr = E_INVALIDARG;
  614. goto HereIsVtArrayGimmieBinary_Exit;
  615. }
  616. if (bReturnBinaryAsVT_VARIANT)
  617. {
  618. hr = VariantChangeType(lpVarSrcObject,lpVarSrcObject,0,VT_ARRAY | VT_VARIANT);
  619. }
  620. else
  621. {
  622. hr = VariantChangeType(lpVarSrcObject,lpVarSrcObject,0,VT_ARRAY | VT_UI1);
  623. }
  624. if (FAILED(hr))
  625. {
  626. if (hr != E_OUTOFMEMORY)
  627. {
  628. hr = OLE_E_CANTCONVERT;
  629. }
  630. goto HereIsVtArrayGimmieBinary_Exit;
  631. }
  632. if (bReturnBinaryAsVT_VARIANT)
  633. {
  634. if( lpVarSrcObject->vt != (VT_ARRAY | VT_VARIANT))
  635. {
  636. hr = OLE_E_CANTCONVERT;
  637. goto HereIsVtArrayGimmieBinary_Exit;
  638. }
  639. }
  640. else
  641. {
  642. if( lpVarSrcObject->vt != (VT_ARRAY | VT_UI1))
  643. {
  644. hr = OLE_E_CANTCONVERT;
  645. goto HereIsVtArrayGimmieBinary_Exit;
  646. }
  647. }
  648. hr = SafeArrayGetLBound(V_ARRAY(lpVarSrcObject),1,(long FAR *) &dwSLBound );
  649. if (FAILED(hr))
  650. {goto HereIsVtArrayGimmieBinary_Exit;}
  651. hr = SafeArrayGetUBound(V_ARRAY(lpVarSrcObject),1,(long FAR *) &dwSUBound );
  652. if (FAILED(hr))
  653. {goto HereIsVtArrayGimmieBinary_Exit;}
  654. //*pbBinaryBuffer = (LPBYTE) AllocADsMem(dwSUBound - dwSLBound + 1);
  655. *pbBinaryBuffer = (char *) ::CoTaskMemAlloc(dwSUBound - dwSLBound + 1);
  656. if (*pbBinaryBuffer == NULL)
  657. {
  658. hr = E_OUTOFMEMORY;
  659. goto HereIsVtArrayGimmieBinary_Exit;
  660. }
  661. *cbBinaryBufferSize = dwSUBound - dwSLBound + 1;
  662. hr = SafeArrayAccessData( V_ARRAY(lpVarSrcObject),(void HUGEP * FAR *) &pArray );
  663. if (FAILED(hr))
  664. {goto HereIsVtArrayGimmieBinary_Exit;}
  665. memcpy(*pbBinaryBuffer,pArray,dwSUBound-dwSLBound+1);
  666. SafeArrayUnaccessData( V_ARRAY(lpVarSrcObject) );
  667. HereIsVtArrayGimmieBinary_Exit:
  668. return hr;
  669. }
  670. BOOL IsCertExportable(PCCERT_CONTEXT pCertContext)
  671. {
  672. HCRYPTPROV hCryptProv = NULL;
  673. DWORD dwKeySpec = 0;
  674. BOOL fCallerFreeProv = FALSE;
  675. BOOL fReturn = FALSE;
  676. HCRYPTKEY hKey = NULL;
  677. DWORD dwPermissions = 0;
  678. DWORD dwSize = 0;
  679. if (!pCertContext)
  680. {
  681. fReturn = FALSE;
  682. goto IsCertExportable_Exit;
  683. }
  684. //
  685. // first get the private key context
  686. //
  687. if (!CryptAcquireCertificatePrivateKey(
  688. pCertContext,
  689. CRYPT_ACQUIRE_USE_PROV_INFO_FLAG | CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
  690. NULL,
  691. &hCryptProv,
  692. &dwKeySpec,
  693. &fCallerFreeProv))
  694. {
  695. fReturn = FALSE;
  696. goto IsCertExportable_Exit;
  697. }
  698. //
  699. // get the handle to the key
  700. //
  701. if (!CryptGetUserKey(hCryptProv, dwKeySpec, &hKey))
  702. {
  703. fReturn = FALSE;
  704. goto IsCertExportable_Exit;
  705. }
  706. //
  707. // finally, get the permissions on the key and check if it is exportable
  708. //
  709. dwSize = sizeof(dwPermissions);
  710. if (!CryptGetKeyParam(hKey, KP_PERMISSIONS, (PBYTE)&dwPermissions, &dwSize, 0))
  711. {
  712. fReturn = FALSE;
  713. goto IsCertExportable_Exit;
  714. }
  715. fReturn = (dwPermissions & CRYPT_EXPORT) ? TRUE : FALSE;
  716. IsCertExportable_Exit:
  717. if (hKey != NULL){CryptDestroyKey(hKey);}
  718. if (fCallerFreeProv){CryptReleaseContext(hCryptProv, 0);}
  719. return fReturn;
  720. }
  721. BOOL FormatDateString(CString& str, FILETIME ft, BOOL fIncludeTime, BOOL fLongFormat)
  722. {
  723. BOOL bReturn = FALSE;
  724. LPWSTR pwReturnedString = NULL;
  725. bReturn = FormatDateString(&pwReturnedString,ft,fIncludeTime,fLongFormat);
  726. if (pwReturnedString)
  727. {
  728. str = pwReturnedString;
  729. free(pwReturnedString);pwReturnedString = NULL;
  730. }
  731. return bReturn;
  732. }
  733. BOOL FormatDateString(LPWSTR * pszReturn, FILETIME ft, BOOL fIncludeTime, BOOL fLongFormat)
  734. {
  735. int cch;
  736. int cch2;
  737. SYSTEMTIME st;
  738. FILETIME localTime;
  739. LPWSTR psz = NULL;
  740. if (!FileTimeToLocalFileTime(&ft, &localTime))
  741. {
  742. return FALSE;
  743. }
  744. if (!FileTimeToSystemTime(&localTime, &st))
  745. {
  746. //
  747. // if the conversion to local time failed, then just use the original time
  748. //
  749. if (!FileTimeToSystemTime(&ft, &st))
  750. {
  751. return FALSE;
  752. }
  753. }
  754. cch = (GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, &st, NULL, NULL, 0) +
  755. GetDateFormat(LOCALE_SYSTEM_DEFAULT, fLongFormat ? DATE_LONGDATE : 0, &st, NULL, NULL, 0) + 5);
  756. if (NULL == (psz = (LPWSTR) malloc((cch+5) * sizeof(WCHAR))))
  757. {
  758. return FALSE;
  759. }
  760. cch2 = GetDateFormat(LOCALE_SYSTEM_DEFAULT, fLongFormat ? DATE_LONGDATE : 0, &st, NULL, psz, cch);
  761. if (fIncludeTime)
  762. {
  763. psz[cch2-1] = ' ';
  764. GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_NOSECONDS, &st, NULL, &psz[cch2], cch-cch2);
  765. }
  766. if (psz)
  767. {
  768. *pszReturn = psz;
  769. return TRUE;
  770. }
  771. else
  772. {
  773. return FALSE;
  774. }
  775. }
  776. const WCHAR RgwchHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
  777. BOOL FormatMemBufToString(LPWSTR *ppString, LPBYTE pbData, DWORD cbData)
  778. {
  779. DWORD i = 0;
  780. LPBYTE pb;
  781. DWORD numCharsInserted = 0;
  782. //
  783. // calculate the size needed
  784. //
  785. pb = pbData;
  786. while (pb <= &(pbData[cbData-1]))
  787. {
  788. if (numCharsInserted == 4)
  789. {
  790. i += sizeof(WCHAR);
  791. numCharsInserted = 0;
  792. }
  793. else
  794. {
  795. i += 2 * sizeof(WCHAR);
  796. pb++;
  797. numCharsInserted += 2;
  798. }
  799. }
  800. if (NULL == (*ppString = (LPWSTR) malloc(i+sizeof(WCHAR))))
  801. {
  802. return FALSE;
  803. }
  804. //
  805. // copy to the buffer
  806. //
  807. i = 0;
  808. numCharsInserted = 0;
  809. pb = pbData;
  810. while (pb <= &(pbData[cbData-1]))
  811. {
  812. if (numCharsInserted == 4)
  813. {
  814. (*ppString)[i++] = L' ';
  815. numCharsInserted = 0;
  816. }
  817. else
  818. {
  819. (*ppString)[i++] = RgwchHex[(*pb & 0xf0) >> 4];
  820. (*ppString)[i++] = RgwchHex[*pb & 0x0f];
  821. pb++;
  822. numCharsInserted += 2;
  823. }
  824. }
  825. (*ppString)[i] = 0;
  826. return TRUE;
  827. }
  828. BOOL MyGetOIDInfo(LPWSTR string, DWORD stringSize, LPSTR pszObjId,BOOL bReturnBackNumericOID)
  829. {
  830. PCCRYPT_OID_INFO pOIDInfo;
  831. if (bReturnBackNumericOID)
  832. {
  833. return (MultiByteToWideChar(CP_ACP, 0, pszObjId, -1, string, stringSize) != 0);
  834. }
  835. else
  836. {
  837. pOIDInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, pszObjId, 0);
  838. if (pOIDInfo != NULL)
  839. {
  840. if ((DWORD)wcslen(pOIDInfo->pwszName)+1 <= stringSize)
  841. {
  842. StringCbCopyW(string,stringSize * sizeof(WCHAR),pOIDInfo->pwszName);
  843. }
  844. else
  845. {
  846. return FALSE;
  847. }
  848. }
  849. else
  850. {
  851. return (MultiByteToWideChar(CP_ACP, 0, pszObjId, -1, string, stringSize) != 0);
  852. }
  853. }
  854. return TRUE;
  855. }
  856. #define CRYPTUI_MAX_STRING_SIZE 768
  857. #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
  858. BOOL FormatEnhancedKeyUsageString(LPWSTR * pszReturn, PCCERT_CONTEXT pCertContext, BOOL fPropertiesOnly)
  859. {
  860. CERT_ENHKEY_USAGE * pKeyUsage = NULL;
  861. WCHAR szText[CRYPTUI_MAX_STRING_SIZE];
  862. BOOL bRes = FALSE;
  863. HRESULT hRes = 0;
  864. LPWSTR pwszTempString = NULL;
  865. void *pTemp = NULL;
  866. DWORD numChars = 128 + 1; // 1 is the terminating null
  867. pwszTempString = (LPWSTR) malloc(numChars * sizeof(WCHAR));
  868. if (pwszTempString == NULL)
  869. {
  870. goto FormatEnhancedKeyUsageString_Exit;
  871. }
  872. ZeroMemory(pwszTempString,numChars * sizeof(WCHAR));
  873. if (GetKeyUsageProperty(pCertContext, &pKeyUsage, fPropertiesOnly, &hRes))
  874. {
  875. // loop for each usage and add it to the display string
  876. for (DWORD i = 0; i < pKeyUsage->cUsageIdentifier; i++)
  877. {
  878. if (!(bRes = MyGetOIDInfo(szText, ARRAYSIZE(szText), pKeyUsage->rgpszUsageIdentifier[i], FALSE)))
  879. break;
  880. // add delimeter if not first iteration
  881. if (i != 0)
  882. {
  883. numChars = numChars + 2;
  884. if ( wcslen(pwszTempString) <= (numChars * sizeof(WCHAR)))
  885. {
  886. pTemp = realloc(pwszTempString, (numChars * sizeof(WCHAR)));
  887. if (pTemp == NULL)
  888. {
  889. free(pwszTempString);pwszTempString = NULL;
  890. }
  891. pwszTempString = (LPWSTR) pTemp;
  892. }
  893. StringCbCatW(pwszTempString,numChars * sizeof(WCHAR),L", ");
  894. }
  895. // add the enhanced key usage string
  896. if ((wcslen(szText) + 1) <= (numChars * sizeof(WCHAR)))
  897. {
  898. numChars = numChars + wcslen(szText) + 1;
  899. pTemp = realloc(pwszTempString, (numChars * sizeof(WCHAR)));
  900. if (pTemp == NULL)
  901. {
  902. free(pwszTempString);pwszTempString = NULL;
  903. }
  904. pwszTempString = (LPWSTR) pTemp;
  905. }
  906. StringCbCatW(pwszTempString,numChars * sizeof(WCHAR),szText);
  907. }
  908. free(pKeyUsage);
  909. }
  910. FormatEnhancedKeyUsageString_Exit:
  911. *pszReturn = pwszTempString;
  912. return bRes;
  913. }
  914. BOOL FormatEnhancedKeyUsageString(CString& str,PCCERT_CONTEXT pCertContext,BOOL fPropertiesOnly,BOOL fMultiline,HRESULT * phRes)
  915. {
  916. CERT_ENHKEY_USAGE * pKeyUsage = NULL;
  917. WCHAR szText[CRYPTUI_MAX_STRING_SIZE];
  918. BOOL bRes = FALSE;
  919. if (GetKeyUsageProperty(pCertContext, &pKeyUsage, fPropertiesOnly, phRes))
  920. {
  921. // loop for each usage and add it to the display string
  922. for (DWORD i = 0; i < pKeyUsage->cUsageIdentifier; i++)
  923. {
  924. if (!(bRes = MyGetOIDInfo(szText, ARRAYSIZE(szText), pKeyUsage->rgpszUsageIdentifier[i],FALSE)))
  925. break;
  926. // add delimeter if not first iteration
  927. if (i != 0)
  928. {
  929. str += fMultiline ? L"\n" : L", ";
  930. }
  931. // add the enhanced key usage string
  932. str += szText;
  933. }
  934. free (pKeyUsage);
  935. }
  936. else
  937. {
  938. str.LoadString(_Module.GetResourceInstance(),IDS_ANY);
  939. bRes = TRUE;
  940. }
  941. return bRes;
  942. }
  943. #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
  944. #define STRING_ALLOCATION_SIZE 128
  945. BOOL GetCertDescriptionForRemote(PCCERT_CONTEXT pCert, LPWSTR *ppString, DWORD * cbReturn, BOOL fMultiline)
  946. {
  947. CERT_NAME_INFO *pNameInfo;
  948. DWORD cbNameInfo;
  949. WCHAR szText[256];
  950. LPWSTR pwszText;
  951. int i,j;
  952. DWORD numChars = 1; // 1 for the terminating 0
  953. DWORD numAllocations = 1;
  954. void *pTemp;
  955. //
  956. // decode the dnname into a CERT_NAME_INFO struct
  957. //
  958. if (!CryptDecodeObject(
  959. X509_ASN_ENCODING,
  960. X509_UNICODE_NAME,
  961. pCert->pCertInfo->Subject.pbData,
  962. pCert->pCertInfo->Subject.cbData,
  963. 0,
  964. NULL,
  965. &cbNameInfo))
  966. {
  967. return FALSE;
  968. }
  969. if (NULL == (pNameInfo = (CERT_NAME_INFO *) malloc(cbNameInfo)))
  970. {
  971. return FALSE;
  972. }
  973. if (!CryptDecodeObject(
  974. X509_ASN_ENCODING,
  975. X509_UNICODE_NAME,
  976. pCert->pCertInfo->Subject.pbData,
  977. pCert->pCertInfo->Subject.cbData,
  978. 0,
  979. pNameInfo,
  980. &cbNameInfo))
  981. {
  982. free(pNameInfo);
  983. return FALSE;
  984. }
  985. //
  986. // allocate an initial buffer for the DN name string, then if it grows larger
  987. // than the initial amount just grow as needed
  988. //
  989. *ppString = (LPWSTR) malloc(STRING_ALLOCATION_SIZE * sizeof(WCHAR));
  990. if (*ppString == NULL)
  991. {
  992. free(pNameInfo);
  993. return FALSE;
  994. }
  995. (*ppString)[0] = 0;
  996. //
  997. // loop for each rdn and add it to the string
  998. //
  999. for (i=pNameInfo->cRDN-1; i>=0; i--)
  1000. {
  1001. // if this is not the first iteration, then add a eol or a ", "
  1002. if (i != (int)pNameInfo->cRDN-1)
  1003. {
  1004. if (numChars+2 >= (numAllocations * STRING_ALLOCATION_SIZE))
  1005. {
  1006. pTemp = realloc(*ppString, ++numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR));
  1007. if (pTemp == NULL)
  1008. {
  1009. free (pNameInfo);
  1010. free (*ppString);
  1011. return FALSE;
  1012. }
  1013. *ppString = (LPWSTR) pTemp;
  1014. }
  1015. if (fMultiline)
  1016. {
  1017. StringCbCatW(*ppString,numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR),L"\n");
  1018. }
  1019. else
  1020. {
  1021. StringCbCatW(*ppString,numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR),L", ");
  1022. }
  1023. numChars += 2;
  1024. }
  1025. for (j=pNameInfo->rgRDN[i].cRDNAttr-1; j>=0; j--)
  1026. {
  1027. // if this is not the first iteration, then add a eol or a ", "
  1028. if (j != (int)pNameInfo->rgRDN[i].cRDNAttr-1)
  1029. {
  1030. if (numChars+2 >= (numAllocations * STRING_ALLOCATION_SIZE))
  1031. {
  1032. pTemp = realloc(*ppString, ++numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR));
  1033. if (pTemp == NULL)
  1034. {
  1035. free (pNameInfo);
  1036. free (*ppString);
  1037. return FALSE;
  1038. }
  1039. *ppString = (LPWSTR) pTemp;
  1040. }
  1041. if (fMultiline)
  1042. {
  1043. StringCbCatW(*ppString,numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR),L"\n");
  1044. }
  1045. else
  1046. {
  1047. StringCbCatW(*ppString,numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR),L", ");
  1048. }
  1049. numChars += 2;
  1050. }
  1051. //
  1052. // add the field name to the string if it is Multiline display
  1053. //
  1054. if (fMultiline)
  1055. {
  1056. if (!MyGetOIDInfo(szText, ARRAYSIZE(szText), pNameInfo->rgRDN[i].rgRDNAttr[j].pszObjId,TRUE))
  1057. {
  1058. free (pNameInfo);
  1059. return FALSE;
  1060. }
  1061. if ((numChars + wcslen(szText) + 3) >= (numAllocations * STRING_ALLOCATION_SIZE))
  1062. {
  1063. // increment the number of allocation blocks until it is large enough
  1064. while ((numChars + wcslen(szText) + 3) >= (++numAllocations * STRING_ALLOCATION_SIZE));
  1065. pTemp = realloc(*ppString, numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR));
  1066. if (pTemp == NULL)
  1067. {
  1068. free (pNameInfo);
  1069. free (*ppString);
  1070. return FALSE;
  1071. }
  1072. *ppString = (LPWSTR) pTemp;
  1073. }
  1074. numChars += wcslen(szText) + 1;
  1075. StringCbCatW(*ppString,numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR),szText);
  1076. StringCbCatW(*ppString,numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR),L"=");
  1077. }
  1078. //
  1079. // add the value to the string
  1080. //
  1081. if (CERT_RDN_ENCODED_BLOB == pNameInfo->rgRDN[i].rgRDNAttr[j].dwValueType ||
  1082. CERT_RDN_OCTET_STRING == pNameInfo->rgRDN[i].rgRDNAttr[j].dwValueType)
  1083. {
  1084. // translate the buffer to a text string and display it that way
  1085. if (FormatMemBufToString(
  1086. &pwszText,
  1087. pNameInfo->rgRDN[i].rgRDNAttr[j].Value.pbData,
  1088. pNameInfo->rgRDN[i].rgRDNAttr[j].Value.cbData))
  1089. {
  1090. if ((numChars + wcslen(pwszText)) >= (numAllocations * STRING_ALLOCATION_SIZE))
  1091. {
  1092. // increment the number of allocation blocks until it is large enough
  1093. while ((numChars + wcslen(pwszText)) >= (++numAllocations * STRING_ALLOCATION_SIZE));
  1094. pTemp = realloc(*ppString, numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR));
  1095. if (pTemp == NULL)
  1096. {
  1097. free (pwszText);
  1098. free (pNameInfo);
  1099. free (*ppString);
  1100. return FALSE;
  1101. }
  1102. *ppString = (LPWSTR) pTemp;
  1103. }
  1104. StringCbCatW(*ppString,numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR),pwszText);
  1105. numChars += wcslen(pwszText);
  1106. free (pwszText);
  1107. }
  1108. }
  1109. else
  1110. {
  1111. // buffer is already a string so just copy it
  1112. if ((numChars + (pNameInfo->rgRDN[i].rgRDNAttr[j].Value.cbData/sizeof(WCHAR)))
  1113. >= (numAllocations * STRING_ALLOCATION_SIZE))
  1114. {
  1115. // increment the number of allocation blocks until it is large enough
  1116. while ((numChars + (pNameInfo->rgRDN[i].rgRDNAttr[j].Value.cbData/sizeof(WCHAR)))
  1117. >= (++numAllocations * STRING_ALLOCATION_SIZE));
  1118. pTemp = realloc(*ppString, numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR));
  1119. if (pTemp == NULL)
  1120. {
  1121. free (pNameInfo);
  1122. free (*ppString);
  1123. return FALSE;
  1124. }
  1125. *ppString = (LPWSTR) pTemp;
  1126. }
  1127. StringCbCatW(*ppString,numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR),(LPWSTR) pNameInfo->rgRDN[i].rgRDNAttr[j].Value.pbData);
  1128. numChars += (pNameInfo->rgRDN[i].rgRDNAttr[j].Value.cbData/sizeof(WCHAR));
  1129. }
  1130. }
  1131. }
  1132. {
  1133. // issued to
  1134. LPWSTR pwName = NULL;
  1135. DWORD cchName = CertGetNameString(pCert, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL, NULL, 0);
  1136. if (cchName > 1 && (NULL != ( pwName = (LPWSTR) malloc (cchName * sizeof(WCHAR) ))))
  1137. {
  1138. BOOL bRes = FALSE;
  1139. bRes = (1 != CertGetNameString(pCert, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL, pwName, cchName));
  1140. if (bRes)
  1141. {
  1142. if ((numChars + 4) >= (numAllocations * STRING_ALLOCATION_SIZE))
  1143. {
  1144. // increment the number of allocation blocks until it is large enough
  1145. while ((numChars + 4) >= (++numAllocations * STRING_ALLOCATION_SIZE));
  1146. pTemp = realloc(*ppString, numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR));
  1147. if (pTemp == NULL)
  1148. {
  1149. free (pwszText);
  1150. free (pNameInfo);
  1151. free (*ppString);
  1152. return FALSE;
  1153. }
  1154. *ppString = (LPWSTR) pTemp;
  1155. }
  1156. StringCbCatW(*ppString,numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR),L"\n");
  1157. numChars += 2;
  1158. // append it on to the string.
  1159. //#define CERT_INFO_ISSUER_FLAG
  1160. StringCbCatW(*ppString,numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR),L"4=");
  1161. numChars += 2;
  1162. // append it on to the string.
  1163. if (wcslen(pwName) > 0)
  1164. {
  1165. if ((numChars + wcslen(pwName)) >= (numAllocations * STRING_ALLOCATION_SIZE))
  1166. {
  1167. // increment the number of allocation blocks until it is large enough
  1168. while ((numChars + wcslen(pwName)) >= (++numAllocations * STRING_ALLOCATION_SIZE));
  1169. pTemp = realloc(*ppString, numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR));
  1170. if (pTemp == NULL)
  1171. {
  1172. free (pwszText);
  1173. free (pNameInfo);
  1174. free (*ppString);
  1175. return FALSE;
  1176. }
  1177. *ppString = (LPWSTR) pTemp;
  1178. }
  1179. StringCbCatW(*ppString,numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR),(LPWSTR) pwName);
  1180. numChars += (cchName);
  1181. }
  1182. }
  1183. if (pwName) {free(pwName);pwName=NULL;}
  1184. }
  1185. // expiration date
  1186. if (FormatDateString(&pwName, pCert->pCertInfo->NotAfter, FALSE, FALSE))
  1187. {
  1188. if ((numChars + 4) >= (numAllocations * STRING_ALLOCATION_SIZE))
  1189. {
  1190. // increment the number of allocation blocks until it is large enough
  1191. while ((numChars + 4) >= (++numAllocations * STRING_ALLOCATION_SIZE));
  1192. pTemp = realloc(*ppString, numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR));
  1193. if (pTemp == NULL)
  1194. {
  1195. free (pwszText);
  1196. free (pNameInfo);
  1197. free (*ppString);
  1198. return FALSE;
  1199. }
  1200. *ppString = (LPWSTR) pTemp;
  1201. }
  1202. StringCbCatW(*ppString,numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR),(LPWSTR) L"\n");
  1203. numChars += 2;
  1204. // append it on to the string.
  1205. //#define CERT_INFO_NOT_AFTER_FLAG 6
  1206. StringCbCatW(*ppString,numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR),(LPWSTR) L"6=");
  1207. numChars += 2;
  1208. // append it on to the string.
  1209. if (wcslen(pwName) > 0)
  1210. {
  1211. if ((numChars + wcslen(pwName)) >= (numAllocations * STRING_ALLOCATION_SIZE))
  1212. {
  1213. // increment the number of allocation blocks until it is large enough
  1214. while ((numChars + wcslen(pwName)) >= (++numAllocations * STRING_ALLOCATION_SIZE));
  1215. pTemp = realloc(*ppString, numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR));
  1216. if (pTemp == NULL)
  1217. {
  1218. free (pwszText);
  1219. free (pNameInfo);
  1220. free (*ppString);
  1221. return FALSE;
  1222. }
  1223. *ppString = (LPWSTR) pTemp;
  1224. }
  1225. StringCbCatW(*ppString,numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR),(LPWSTR) pwName);
  1226. numChars += wcslen(pwName);
  1227. }
  1228. if (pwName) {free(pwName);pwName = NULL;}
  1229. }
  1230. // purpose
  1231. if (FormatEnhancedKeyUsageString(&pwName, pCert, FALSE))
  1232. {
  1233. if ((numChars + 12) >= (numAllocations * STRING_ALLOCATION_SIZE))
  1234. {
  1235. // increment the number of allocation blocks until it is large enough
  1236. while ((numChars + 12) >= (++numAllocations * STRING_ALLOCATION_SIZE));
  1237. pTemp = realloc(*ppString, numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR));
  1238. if (pTemp == NULL)
  1239. {
  1240. free (pwszText);
  1241. free (pNameInfo);
  1242. free (*ppString);
  1243. return FALSE;
  1244. }
  1245. *ppString = (LPWSTR) pTemp;
  1246. }
  1247. StringCbCatW(*ppString,numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR),(LPWSTR) L"\n");
  1248. numChars += 2;
  1249. // append it on to the string.
  1250. //#define szOID_ENHANCED_KEY_USAGE "2.5.29.37"
  1251. StringCbCatW(*ppString,numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR),(LPWSTR) L"2.5.29.37=");
  1252. numChars += 10;
  1253. // append it on to the string.
  1254. if (wcslen(pwName) > 0)
  1255. {
  1256. if ((numChars + wcslen(pwName)) >= (numAllocations * STRING_ALLOCATION_SIZE))
  1257. {
  1258. // increment the number of allocation blocks until it is large enough
  1259. while ((numChars + wcslen(pwName)) >= (++numAllocations * STRING_ALLOCATION_SIZE));
  1260. pTemp = realloc(*ppString, numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR));
  1261. if (pTemp == NULL)
  1262. {
  1263. free (pwszText);
  1264. free (pNameInfo);
  1265. free (*ppString);
  1266. return FALSE;
  1267. }
  1268. *ppString = (LPWSTR) pTemp;
  1269. }
  1270. StringCbCatW(*ppString,numAllocations * STRING_ALLOCATION_SIZE * sizeof(WCHAR),(LPWSTR) pwName);
  1271. numChars += wcslen(pwName);
  1272. }
  1273. if (pwName) {free(pwName);pwName = NULL;}
  1274. }
  1275. }
  1276. *cbReturn = numChars;
  1277. free (pNameInfo);
  1278. return TRUE;
  1279. }
  1280. //+----------------------------------------------------------------------------
  1281. //
  1282. // Function: CreateFolders
  1283. //
  1284. // Synopsis: Creates any missing directories for any slash delimited folder
  1285. // names in the path.
  1286. //
  1287. // Arguments: [ptszPathName] - the path name
  1288. // [fHasFileName] - if true, the path name includes a file name.
  1289. //
  1290. // Returns: HRESULTS
  1291. //
  1292. // Notes: ptszPathName should never end in a slash.
  1293. // Treats forward and back slashes identically.
  1294. //-----------------------------------------------------------------------------
  1295. #define s_isDriveLetter(c) ((c >= TEXT('a') && c <= TEXT('z')) || (c >= TEXT('A') && c <= TEXT('Z')))
  1296. HRESULT
  1297. CreateFolders(LPCTSTR ptszPathName, BOOL fHasFileName)
  1298. {
  1299. DWORD dwLen = 0;
  1300. //
  1301. // Copy the string so we can munge it
  1302. //
  1303. dwLen = lstrlen(ptszPathName) + 2;
  1304. TCHAR * ptszPath = new TCHAR[dwLen];
  1305. if (!ptszPath)
  1306. {
  1307. return E_OUTOFMEMORY;
  1308. }
  1309. StringCbCopy(ptszPath,dwLen * sizeof(TCHAR),ptszPathName);
  1310. if (!fHasFileName)
  1311. {
  1312. //
  1313. // If no file name, append a slash so the following logic works
  1314. // correctly.
  1315. //
  1316. StringCbCat(ptszPath,dwLen * sizeof(TCHAR),TEXT("\\"));
  1317. }
  1318. //
  1319. // Get a pointer to the last slash in the name.
  1320. //
  1321. TCHAR * ptszSlash = _tcsrchr(ptszPath, TEXT('\\'));
  1322. if (ptszSlash == NULL)
  1323. {
  1324. //
  1325. // no slashes found, so nothing to do
  1326. //
  1327. delete [] ptszPath;
  1328. return S_OK;
  1329. }
  1330. if (fHasFileName)
  1331. {
  1332. //
  1333. // Chop off the file name, leaving the slash as the last char.
  1334. //
  1335. ptszSlash[1] = TEXT('\0');
  1336. }
  1337. BOOL fFullPath = (lstrlen(ptszPath) > 2 &&
  1338. s_isDriveLetter(ptszPath[0]) &&
  1339. ptszPath[1] == TEXT(':'));
  1340. //
  1341. // Walk the string looking for slashes. Each found slash is temporarily
  1342. // replaced with a null and that substring passed to CreateDir.
  1343. //
  1344. TCHAR * ptszTail = ptszPath;
  1345. while (ptszSlash = _tcspbrk(ptszTail, TEXT("\\/")))
  1346. {
  1347. //
  1348. // If the path name starts like C:\ then the first slash will be at
  1349. // the third character
  1350. //
  1351. if (fFullPath && (ptszSlash - ptszTail == 2))
  1352. {
  1353. //
  1354. // We are looking at the root of the drive, so don't try to create
  1355. // a root directory.
  1356. //
  1357. ptszTail = ptszSlash + 1;
  1358. continue;
  1359. }
  1360. *ptszSlash = TEXT('\0');
  1361. if (!CreateDirectory(ptszPath, NULL))
  1362. {
  1363. DWORD dwErr = GetLastError();
  1364. if (dwErr != ERROR_ALREADY_EXISTS)
  1365. {
  1366. delete [] ptszPath;
  1367. return (HRESULT_FROM_WIN32(dwErr));
  1368. }
  1369. }
  1370. *ptszSlash = TEXT('\\');
  1371. ptszTail = ptszSlash + 1;
  1372. }
  1373. delete [] ptszPath;
  1374. return S_OK;
  1375. }
  1376. #ifdef USE_CERT_REQUEST_OBJECT
  1377. HRESULT
  1378. CreateRequest_Base64(const BSTR bstr_dn,
  1379. IEnroll * pEnroll,
  1380. BSTR csp_name,
  1381. DWORD csp_type,
  1382. BSTR * pOut)
  1383. {
  1384. ASSERT(pOut != NULL);
  1385. ASSERT(bstr_dn != NULL);
  1386. HRESULT hRes = S_OK;
  1387. CString strUsage(szOID_PKIX_KP_SERVER_AUTH);
  1388. CRYPT_DATA_BLOB request = {0, NULL};
  1389. pEnroll->put_ProviderType(csp_type);
  1390. pEnroll->put_ProviderNameWStr(csp_name);
  1391. if (csp_type == PROV_DH_SCHANNEL)
  1392. {
  1393. pEnroll->put_KeySpec(AT_SIGNATURE);
  1394. }
  1395. else if (csp_type == PROV_RSA_SCHANNEL)
  1396. {
  1397. pEnroll->put_KeySpec(AT_KEYEXCHANGE);
  1398. }
  1399. if (SUCCEEDED(hRes = pEnroll->createPKCS10WStr(
  1400. bstr_dn,
  1401. (LPTSTR)(LPCTSTR)strUsage,
  1402. &request)))
  1403. {
  1404. WCHAR * wszRequestB64 = NULL;
  1405. DWORD cch = 0;
  1406. DWORD err = ERROR_SUCCESS;
  1407. // BASE64 encode pkcs 10
  1408. if ((err = Base64EncodeW(request.pbData, request.cbData, NULL, &cch)) == ERROR_SUCCESS )
  1409. {
  1410. wszRequestB64 = (WCHAR *) LocalAlloc(cch * sizeof(WCHAR));;
  1411. if (NULL != wszRequestB64)
  1412. {
  1413. if ((err = Base64EncodeW(request.pbData, request.cbData, wszRequestB64, &cch)) == ERROR_SUCCESS)
  1414. {
  1415. if ((*pOut = SysAllocStringLen(wszRequestB64, cch)) == NULL )
  1416. {
  1417. hRes = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
  1418. }
  1419. }
  1420. else
  1421. {
  1422. hRes = HRESULT_FROM_WIN32(err);
  1423. }
  1424. }
  1425. else
  1426. {
  1427. hRes = HRESULT_FROM_WIN32(err);
  1428. }
  1429. if (wszRequestB64)
  1430. {
  1431. LocalFree(wszRequestB64);
  1432. wszRequestB64 = NULL;
  1433. }
  1434. }
  1435. else
  1436. {
  1437. hRes = HRESULT_FROM_WIN32(err);
  1438. }
  1439. if (request.pbData != NULL)
  1440. CoTaskMemFree(request.pbData);
  1441. }
  1442. return hRes;
  1443. }
  1444. PCCERT_CONTEXT GetCertContextFromPKCS7(const BYTE * pbData,DWORD cbData,CERT_PUBLIC_KEY_INFO * pKeyInfo,HRESULT * phResult)
  1445. {
  1446. ASSERT(phResult != NULL);
  1447. PCCERT_CONTEXT pRes = NULL;
  1448. CRYPT_DATA_BLOB blob;
  1449. memset(&blob, 0, sizeof(CRYPT_DATA_BLOB));
  1450. blob.cbData = cbData;
  1451. blob.pbData = (BYTE *)pbData;
  1452. HCERTSTORE hStoreMsg = NULL;
  1453. if(CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
  1454. &blob,
  1455. (CERT_QUERY_CONTENT_FLAG_CERT |
  1456. CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
  1457. CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE |
  1458. CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED) ,
  1459. CERT_QUERY_FORMAT_FLAG_ALL,
  1460. 0,
  1461. NULL,
  1462. NULL,
  1463. NULL,
  1464. &hStoreMsg,
  1465. NULL,
  1466. NULL))
  1467. {
  1468. if (pKeyInfo != NULL)
  1469. pRes = CertFindCertificateInStore(hStoreMsg,
  1470. X509_ASN_ENCODING,
  1471. 0,
  1472. CERT_FIND_PUBLIC_KEY,
  1473. pKeyInfo,
  1474. NULL);
  1475. else
  1476. pRes = CertFindCertificateInStore(hStoreMsg,
  1477. X509_ASN_ENCODING,
  1478. 0,
  1479. CERT_FIND_ANY,
  1480. NULL,
  1481. NULL);
  1482. if (pRes == NULL)
  1483. *phResult = HRESULT_FROM_WIN32(GetLastError());
  1484. CertCloseStore(hStoreMsg, CERT_CLOSE_STORE_CHECK_FLAG);
  1485. }
  1486. else
  1487. *phResult = HRESULT_FROM_WIN32(GetLastError());
  1488. return pRes;
  1489. }
  1490. BOOL
  1491. AttachFriendlyName(PCCERT_CONTEXT pContext,
  1492. const CString& name,
  1493. HRESULT * phRes)
  1494. {
  1495. BOOL bRes = TRUE;
  1496. CRYPT_DATA_BLOB blob_name;
  1497. // Check if friendlyname is empty
  1498. // if it is then don't try to set the friendly name
  1499. if (!name.IsEmpty())
  1500. {
  1501. blob_name.pbData = (LPBYTE)(LPCTSTR)name;
  1502. blob_name.cbData = (name.GetLength() + 1) * sizeof(WCHAR);
  1503. if (!(bRes = CertSetCertificateContextProperty(pContext,
  1504. CERT_FRIENDLY_NAME_PROP_ID, 0, &blob_name)))
  1505. {
  1506. ASSERT(phRes != NULL);
  1507. *phRes = HRESULT_FROM_WIN32(GetLastError());
  1508. }
  1509. }
  1510. return bRes;
  1511. }
  1512. /*
  1513. InstallHashToMetabase
  1514. Function writes hash array to metabase. After that IIS
  1515. could use certificate with that hash from MY store.
  1516. Function expects server_name in format lm\w3svc\<number>,
  1517. i.e. from root node down to virtual server
  1518. */
  1519. BOOL InstallHashToMetabase(CRYPT_HASH_BLOB * pHash,const CString& machine_name, const CString& server_name,HRESULT * phResult)
  1520. {
  1521. BOOL bRes = FALSE;
  1522. CComAuthInfo auth(machine_name);
  1523. CMetaKey key(&auth, server_name,
  1524. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE
  1525. );
  1526. if (key.Succeeded())
  1527. {
  1528. CBlob blob;
  1529. blob.SetValue(pHash->cbData, pHash->pbData, TRUE);
  1530. bRes = SUCCEEDED(*phResult = key.SetValue(MD_SSL_CERT_HASH, blob))
  1531. && SUCCEEDED(*phResult = key.SetValue(MD_SSL_CERT_STORE_NAME, CString(L"MY")));
  1532. }
  1533. else
  1534. {
  1535. TRACE(_T("Failed to open metabase key. Error 0x%x\n"), key.QueryResult());
  1536. *phResult = key.QueryResult();
  1537. }
  1538. return bRes;
  1539. }
  1540. HCERTSTORE
  1541. OpenMyStore(IEnroll * pEnroll, HRESULT * phResult)
  1542. {
  1543. ASSERT(NULL != phResult);
  1544. HCERTSTORE hStore = NULL;
  1545. BSTR bstrStoreName, bstrStoreType;
  1546. long dwStoreFlags;
  1547. VERIFY(SUCCEEDED(pEnroll->get_MyStoreNameWStr(&bstrStoreName)));
  1548. VERIFY(SUCCEEDED(pEnroll->get_MyStoreTypeWStr(&bstrStoreType)));
  1549. VERIFY(SUCCEEDED(pEnroll->get_MyStoreFlags(&dwStoreFlags)));
  1550. size_t store_type_len = _tcslen(bstrStoreType);
  1551. char * szStoreProvider = (char *)_alloca(store_type_len + 1);
  1552. ASSERT(szStoreProvider != NULL);
  1553. size_t n = wcstombs(szStoreProvider, bstrStoreType, store_type_len);
  1554. ASSERT(n != -1);
  1555. // this converter doesn't set zero byte!!!
  1556. szStoreProvider[n] = '\0';
  1557. hStore = CertOpenStore(
  1558. szStoreProvider,
  1559. PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  1560. NULL,
  1561. dwStoreFlags,
  1562. bstrStoreName
  1563. );
  1564. CoTaskMemFree(bstrStoreName);
  1565. CoTaskMemFree(bstrStoreType);
  1566. if (hStore == NULL)
  1567. *phResult = HRESULT_FROM_WIN32(GetLastError());
  1568. return hStore;
  1569. }
  1570. /*
  1571. GetInstalledCert
  1572. Function reads cert hash attribute from metabase
  1573. using machine_name and server name as server instance
  1574. description, then looks in MY store for a certificate
  1575. with hash equal found in metabase.
  1576. Return is cert context pointer or NULL, if cert wasn't
  1577. found or certificate store wasn't opened.
  1578. On return HRESULT * is filled by error code.
  1579. */
  1580. PCCERT_CONTEXT GetInstalledCert(const CString& machine_name, const CString& server_name,IEnroll * pEnroll,HRESULT * phResult)
  1581. {
  1582. ASSERT(pEnroll != NULL);
  1583. ASSERT(phResult != NULL);
  1584. ASSERT(!machine_name.IsEmpty());
  1585. ASSERT(!server_name.IsEmpty());
  1586. PCCERT_CONTEXT pCert = NULL;
  1587. *phResult = S_OK;
  1588. CComAuthInfo auth(machine_name);
  1589. CMetaKey key(&auth, server_name,
  1590. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE
  1591. );
  1592. if (key.Succeeded())
  1593. {
  1594. CString store_name;
  1595. CBlob hash;
  1596. if ( SUCCEEDED(*phResult = key.QueryValue(MD_SSL_CERT_STORE_NAME, store_name))
  1597. && SUCCEEDED(*phResult = key.QueryValue(MD_SSL_CERT_HASH, hash))
  1598. )
  1599. {
  1600. // Open MY store. We assume that store type and flags
  1601. // cannot be changed between installation and unistallation
  1602. // of the sertificate.
  1603. HCERTSTORE hStore = OpenMyStore(pEnroll, phResult);
  1604. ASSERT(hStore != NULL);
  1605. if (hStore != NULL)
  1606. {
  1607. // Now we need to find cert by hash
  1608. CRYPT_HASH_BLOB crypt_hash;
  1609. SecureZeroMemory(&crypt_hash, sizeof(CRYPT_HASH_BLOB));
  1610. crypt_hash.cbData = hash.GetSize();
  1611. crypt_hash.pbData = hash.GetData();
  1612. pCert = CertFindCertificateInStore(hStore,
  1613. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1614. 0, CERT_FIND_HASH, (LPVOID)&crypt_hash, NULL);
  1615. if (pCert == NULL)
  1616. *phResult = HRESULT_FROM_WIN32(GetLastError());
  1617. VERIFY(CertCloseStore(hStore, 0));
  1618. }
  1619. }
  1620. }
  1621. else
  1622. {
  1623. *phResult = key.QueryResult();
  1624. }
  1625. return pCert;
  1626. }
  1627. void FormatRdnAttr(CString& str, DWORD dwValueType, CRYPT_DATA_BLOB& blob, BOOL fAppend)
  1628. {
  1629. if (CERT_RDN_ENCODED_BLOB == dwValueType || CERT_RDN_OCTET_STRING == dwValueType)
  1630. {
  1631. // translate the buffer to a text string
  1632. LPWSTR pString = NULL;
  1633. FormatMemBufToString(&pString, blob.pbData, blob.cbData);
  1634. if (pString)
  1635. {
  1636. str = pString;
  1637. free(pString);
  1638. }
  1639. }
  1640. else
  1641. {
  1642. // buffer is already a string so just copy/append to it
  1643. if (fAppend)
  1644. {
  1645. str += (LPTSTR)blob.pbData;
  1646. }
  1647. else
  1648. {
  1649. // don't concatenate these entries...
  1650. str = (LPTSTR)blob.pbData;
  1651. }
  1652. }
  1653. }
  1654. BOOL GetNameString(PCCERT_CONTEXT pCertContext,DWORD type,DWORD flag,CString& name,HRESULT * phRes)
  1655. {
  1656. BOOL bRes = FALSE;
  1657. LPTSTR pName = NULL;
  1658. DWORD cchName = CertGetNameString(pCertContext, type, flag, NULL, NULL, 0);
  1659. if (cchName > 1)
  1660. {
  1661. pName = (LPTSTR) LocalAlloc(LPTR, cchName*sizeof(TCHAR));
  1662. if (!pName)
  1663. {
  1664. *phRes = HRESULT_FROM_WIN32(GetLastError());
  1665. return FALSE;
  1666. }
  1667. bRes = (1 != CertGetNameString(pCertContext, type, flag, NULL, pName, cchName));
  1668. if (pName)
  1669. {
  1670. // assign it to the cstring
  1671. name = pName;
  1672. }
  1673. if (pName)
  1674. {
  1675. LocalFree(pName);pName=NULL;
  1676. }
  1677. }
  1678. else
  1679. {
  1680. *phRes = HRESULT_FROM_WIN32(GetLastError());
  1681. }
  1682. return bRes;
  1683. }
  1684. BOOL GetFriendlyName(PCCERT_CONTEXT pCertContext,CString& name,HRESULT * phRes)
  1685. {
  1686. BOOL bRes = FALSE;
  1687. DWORD cb;
  1688. LPTSTR pName = NULL;
  1689. if (!CertGetCertificateContextProperty(pCertContext, CERT_FRIENDLY_NAME_PROP_ID, NULL, &cb))
  1690. {
  1691. *phRes = HRESULT_FROM_WIN32(GetLastError());
  1692. return FALSE;
  1693. }
  1694. if (cb > 1)
  1695. {
  1696. pName = (LPTSTR) LocalAlloc(LPTR, cb * sizeof(TCHAR));
  1697. if (!pName)
  1698. {
  1699. *phRes = HRESULT_FROM_WIN32(GetLastError());
  1700. return FALSE;
  1701. }
  1702. if (CertGetCertificateContextProperty(pCertContext, CERT_FRIENDLY_NAME_PROP_ID, pName, &cb))
  1703. {
  1704. pName[cb] = 0;
  1705. bRes = TRUE;
  1706. }
  1707. else
  1708. {
  1709. *phRes = HRESULT_FROM_WIN32(GetLastError());
  1710. }
  1711. if (pName)
  1712. {
  1713. LocalFree(pName);pName=NULL;
  1714. }
  1715. }
  1716. return bRes;
  1717. }
  1718. BOOL GetAlternateSubjectName(PCCERT_CONTEXT pCertContext,TCHAR ** cwszOut)
  1719. {
  1720. BOOL bRet = FALSE;
  1721. PCERT_ALT_NAME_INFO pAltNameInfo = NULL;
  1722. *cwszOut = NULL;
  1723. pAltNameInfo = AllocAndGetAltSubjectInfo(pCertContext);
  1724. if (pAltNameInfo)
  1725. {
  1726. if (!GetAltNameUnicodeStringChoiceW(CERT_ALT_NAME_RFC822_NAME,pAltNameInfo,cwszOut))
  1727. {
  1728. if (!GetAltNameUnicodeStringChoiceW(CERT_ALT_NAME_DNS_NAME,pAltNameInfo,cwszOut))
  1729. {
  1730. cwszOut = NULL;
  1731. bRet = TRUE;
  1732. }
  1733. }
  1734. }
  1735. if (pAltNameInfo){LocalFree(pAltNameInfo);pAltNameInfo=NULL;}
  1736. return bRet;
  1737. }
  1738. BOOL GetRequestInfoFromPKCS10(CCryptBlob& pkcs10, PCERT_REQUEST_INFO * pReqInfo,HRESULT * phRes)
  1739. {
  1740. ASSERT(pReqInfo != NULL);
  1741. ASSERT(phRes != NULL);
  1742. BOOL bRes = FALSE;
  1743. DWORD req_info_size;
  1744. if (!(bRes = CryptDecodeObjectEx(
  1745. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1746. X509_CERT_REQUEST_TO_BE_SIGNED,
  1747. pkcs10.GetData(),
  1748. pkcs10.GetSize(),
  1749. CRYPT_DECODE_ALLOC_FLAG,
  1750. NULL,
  1751. pReqInfo,
  1752. &req_info_size)))
  1753. {
  1754. TRACE(_T("Error from CryptDecodeObjectEx: %xd\n"), GetLastError());
  1755. *phRes = HRESULT_FROM_WIN32(GetLastError());
  1756. }
  1757. return bRes;
  1758. }
  1759. BOOL EncodeString(CString& str,CCryptBlob& blob,HRESULT * phRes)
  1760. {
  1761. BOOL bRes = FALSE;
  1762. DWORD cb;
  1763. CERT_NAME_VALUE name_value;
  1764. name_value.dwValueType = CERT_RDN_BMP_STRING;
  1765. name_value.Value.cbData = 0;
  1766. name_value.Value.pbData = (LPBYTE)(LPCTSTR)str;
  1767. if ( CryptEncodeObject(CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING,
  1768. &name_value, NULL, &cb)
  1769. && blob.Resize(cb)
  1770. && CryptEncodeObject(CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING,
  1771. &name_value, blob.GetData(), &cb)
  1772. )
  1773. {
  1774. bRes = TRUE;
  1775. }
  1776. else
  1777. *phRes = HRESULT_FROM_WIN32(GetLastError());
  1778. return bRes;
  1779. }
  1780. BOOL EncodeInteger(int number,CCryptBlob& blob,HRESULT * phRes)
  1781. {
  1782. BOOL bRes = FALSE;
  1783. DWORD cb;
  1784. if ( CryptEncodeObject(CRYPT_ASN_ENCODING, X509_INTEGER,
  1785. &number, NULL, &cb)
  1786. && blob.Resize(cb)
  1787. && CryptEncodeObject(CRYPT_ASN_ENCODING, X509_INTEGER,
  1788. &number, blob.GetData(), &cb)
  1789. )
  1790. {
  1791. bRes = TRUE;
  1792. }
  1793. else
  1794. *phRes = HRESULT_FROM_WIN32(GetLastError());
  1795. return bRes;
  1796. }
  1797. HCERTSTORE OpenRequestStore(IEnroll * pEnroll, HRESULT * phResult)
  1798. {
  1799. ASSERT(NULL != phResult);
  1800. HCERTSTORE hStore = NULL;
  1801. WCHAR * bstrStoreName, * bstrStoreType;
  1802. long dwStoreFlags;
  1803. VERIFY(SUCCEEDED(pEnroll->get_RequestStoreNameWStr(&bstrStoreName)));
  1804. VERIFY(SUCCEEDED(pEnroll->get_RequestStoreTypeWStr(&bstrStoreType)));
  1805. VERIFY(SUCCEEDED(pEnroll->get_RequestStoreFlags(&dwStoreFlags)));
  1806. size_t store_type_len = _tcslen(bstrStoreType);
  1807. char * szStoreProvider = (char *)_alloca(store_type_len + 1);
  1808. ASSERT(szStoreProvider != NULL);
  1809. size_t n = wcstombs(szStoreProvider, bstrStoreType, store_type_len);
  1810. szStoreProvider[n] = '\0';
  1811. hStore = CertOpenStore(
  1812. szStoreProvider,
  1813. PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  1814. NULL,
  1815. dwStoreFlags,
  1816. bstrStoreName
  1817. );
  1818. CoTaskMemFree(bstrStoreName);
  1819. CoTaskMemFree(bstrStoreType);
  1820. if (hStore == NULL)
  1821. *phResult = HRESULT_FROM_WIN32(GetLastError());
  1822. return hStore;
  1823. }
  1824. BOOL CreateDirectoryFromPath(LPCTSTR szPath, LPSECURITY_ATTRIBUTES lpSA)
  1825. /*++
  1826. Routine Description:
  1827. Creates the directory specified in szPath and any other "higher"
  1828. directories in the specified path that don't exist.
  1829. Arguments:
  1830. IN LPCTSTR szPath
  1831. directory path to create (assumed to be a DOS path, not a UNC)
  1832. IN LPSECURITY_ATTRIBUTES lpSA
  1833. pointer to security attributes argument used by CreateDirectory
  1834. Return Value:
  1835. TRUE if directory(ies) created
  1836. FALSE if error (GetLastError to find out why)
  1837. --*/
  1838. {
  1839. LPTSTR pLeftHalf, pNext;
  1840. CString RightHalf;
  1841. // 1. We are supporting only absolute paths. Caller should decide which
  1842. // root to use and build the path
  1843. if (PathIsRelative(szPath))
  1844. {
  1845. ASSERT(FALSE);
  1846. return FALSE;
  1847. }
  1848. pLeftHalf = (LPTSTR)szPath;
  1849. pNext = PathSkipRoot(pLeftHalf);
  1850. do {
  1851. // copy the chunk between pLeftHalf and pNext to the
  1852. // local buffer
  1853. while (pLeftHalf < pNext)
  1854. RightHalf += *pLeftHalf++;
  1855. // check if new path exists
  1856. int index = RightHalf.GetLength() - 1;
  1857. BOOL bBackslash = FALSE, bContinue = FALSE;
  1858. if (bBackslash = (RightHalf[index] == L'\\'))
  1859. {
  1860. RightHalf.SetAt(index, 0);
  1861. }
  1862. bContinue = PathIsUNCServerShare(RightHalf);
  1863. if (bBackslash)
  1864. RightHalf.SetAt(index, L'\\');
  1865. if (bContinue || PathIsDirectory(RightHalf))
  1866. continue;
  1867. else if (PathFileExists(RightHalf))
  1868. {
  1869. // we cannot create this directory
  1870. // because file with this name already exists
  1871. SetLastError(ERROR_ALREADY_EXISTS);
  1872. return FALSE;
  1873. }
  1874. else
  1875. {
  1876. // no file no directory, create
  1877. if (!CreateDirectory(RightHalf, lpSA))
  1878. return FALSE;
  1879. }
  1880. }
  1881. while (NULL != (pNext = PathFindNextComponent(pLeftHalf)));
  1882. return TRUE;
  1883. }
  1884. //+-------------------------------------------------------------------------
  1885. // Returns pointer to allocated CERT_ALT_NAME_INFO by decoding either the
  1886. // Subject or Issuer Alternative Extension. CERT_NAME_ISSUER_FLAG is
  1887. // set to select the Issuer.
  1888. //
  1889. // Returns NULL if extension not found or cAltEntry == 0
  1890. //--------------------------------------------------------------------------
  1891. static const LPCSTR rgpszSubjectAltOID[] =
  1892. {
  1893. szOID_SUBJECT_ALT_NAME2,
  1894. szOID_SUBJECT_ALT_NAME
  1895. };
  1896. #define NUM_SUBJECT_ALT_OID (sizeof(rgpszSubjectAltOID) / sizeof(rgpszSubjectAltOID[0]))
  1897. void *AllocAndDecodeObject(
  1898. IN DWORD dwCertEncodingType,
  1899. IN LPCSTR lpszStructType,
  1900. IN const BYTE *pbEncoded,
  1901. IN DWORD cbEncoded,
  1902. IN DWORD dwFlags,
  1903. OUT OPTIONAL DWORD *pcbStructInfo = NULL
  1904. )
  1905. {
  1906. DWORD cbStructInfo;
  1907. void *pvStructInfo;
  1908. if (!CryptDecodeObjectEx(
  1909. dwCertEncodingType,
  1910. lpszStructType,
  1911. pbEncoded,
  1912. cbEncoded,
  1913. dwFlags | CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
  1914. NULL,
  1915. (void *) &pvStructInfo,
  1916. &cbStructInfo
  1917. ))
  1918. goto ErrorReturn;
  1919. CommonReturn:
  1920. if (pcbStructInfo)
  1921. {
  1922. *pcbStructInfo = cbStructInfo;
  1923. }
  1924. return pvStructInfo;
  1925. ErrorReturn:
  1926. pvStructInfo = NULL;
  1927. cbStructInfo = 0;
  1928. goto CommonReturn;
  1929. }
  1930. PCERT_ALT_NAME_INFO AllocAndGetAltSubjectInfo(IN PCCERT_CONTEXT pCertContext)
  1931. {
  1932. DWORD cAltOID;
  1933. const LPCSTR *ppszAltOID;
  1934. PCERT_EXTENSION pExt;
  1935. PCERT_ALT_NAME_INFO pInfo;
  1936. cAltOID = NUM_SUBJECT_ALT_OID;
  1937. ppszAltOID = rgpszSubjectAltOID;
  1938. // Try to find an alternative name extension
  1939. pExt = NULL;
  1940. for ( ; cAltOID > 0; cAltOID--, ppszAltOID++)
  1941. {
  1942. if (pExt = CertFindExtension(*ppszAltOID,pCertContext->pCertInfo->cExtension,pCertContext->pCertInfo->rgExtension))
  1943. {
  1944. break;
  1945. }
  1946. }
  1947. if (NULL == pExt)
  1948. {
  1949. return NULL;
  1950. }
  1951. if (NULL == (pInfo = (PCERT_ALT_NAME_INFO) AllocAndDecodeObject(pCertContext->dwCertEncodingType,X509_ALTERNATE_NAME,pExt->Value.pbData,pExt->Value.cbData,0)))
  1952. {
  1953. return NULL;
  1954. }
  1955. if (0 == pInfo->cAltEntry)
  1956. {
  1957. LocalFree(pInfo);
  1958. pInfo = NULL;
  1959. return NULL;
  1960. }
  1961. else
  1962. {
  1963. return pInfo;
  1964. }
  1965. }
  1966. //+-------------------------------------------------------------------------
  1967. // Attempt to find the specified choice in the decoded alternative name
  1968. // extension.
  1969. //--------------------------------------------------------------------------
  1970. BOOL GetAltNameUnicodeStringChoiceW(IN DWORD dwAltNameChoice,IN PCERT_ALT_NAME_INFO pAltNameInfo,OUT TCHAR **pcwszOut)
  1971. {
  1972. DWORD cEntry;
  1973. PCERT_ALT_NAME_ENTRY pEntry;
  1974. if (NULL == pAltNameInfo)
  1975. {
  1976. return FALSE;
  1977. }
  1978. cEntry = pAltNameInfo->cAltEntry;
  1979. pEntry = pAltNameInfo->rgAltEntry;
  1980. for ( ; cEntry > 0; cEntry--, pEntry++)
  1981. {
  1982. if (dwAltNameChoice == pEntry->dwAltNameChoice)
  1983. {
  1984. // pwszRfc822Name union choice is the same as
  1985. // pwszDNSName and pwszURL.
  1986. // This is it, copy it out to a new allocation
  1987. if (pEntry->pwszRfc822Name)
  1988. {
  1989. *pcwszOut = NULL;
  1990. DWORD cbLen = sizeof(TCHAR) * (lstrlen(pEntry->pwszRfc822Name)+1);
  1991. if(*pcwszOut = (TCHAR *) LocalAlloc(LPTR, cbLen))
  1992. {
  1993. StringCbCopy(*pcwszOut,cbLen,pEntry->pwszRfc822Name);
  1994. return TRUE;
  1995. }
  1996. }
  1997. }
  1998. }
  1999. return FALSE;
  2000. }
  2001. BOOL GetStringProperty(PCCERT_CONTEXT pCertContext,DWORD propId,CString& str,HRESULT * phRes)
  2002. {
  2003. BOOL bRes = FALSE;
  2004. DWORD cb;
  2005. BYTE * prop;
  2006. // compare property value
  2007. if (CertGetCertificateContextProperty(pCertContext, propId, NULL, &cb))
  2008. {
  2009. prop = (BYTE *) LocalAlloc(cb);
  2010. if(NULL != prop)
  2011. {
  2012. if (CertGetCertificateContextProperty(pCertContext, propId, prop, &cb))
  2013. {
  2014. // decode this instance name property
  2015. DWORD cbData = 0;
  2016. void * pData = NULL;
  2017. if (CryptDecodeObject(CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING,prop, cb, 0, NULL, &cbData))
  2018. {
  2019. pData = LocalAlloc(cbData);
  2020. if (NULL != pData)
  2021. {
  2022. if (CryptDecodeObject(CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING,prop, cb, 0, pData, &cbData))
  2023. {
  2024. CERT_NAME_VALUE * pName = (CERT_NAME_VALUE *)pData;
  2025. DWORD cch = pName->Value.cbData/sizeof(TCHAR);
  2026. LPTSTR pValue = (LPTSTR) LocalAlloc(LPTR, (cch+1) * sizeof(TCHAR));
  2027. memcpy(pValue, pName->Value.pbData, pName->Value.cbData);
  2028. str = pValue;
  2029. /*
  2030. void * p = str.GetBuffer(cch);
  2031. memcpy(p, pName->Value.pbData, pName->Value.cbData);
  2032. str.ReleaseBuffer(cch);
  2033. */
  2034. if (pValue)
  2035. {
  2036. LocalFree(pValue);pValue=NULL;
  2037. }
  2038. bRes = TRUE;
  2039. }
  2040. if (pData)
  2041. {
  2042. LocalFree(pData);
  2043. pData = NULL;
  2044. }
  2045. }
  2046. }
  2047. }
  2048. if (prop)
  2049. {
  2050. LocalFree(prop);
  2051. prop=NULL;
  2052. }
  2053. }
  2054. }
  2055. if (!bRes)
  2056. {
  2057. *phRes = HRESULT_FROM_WIN32(GetLastError());
  2058. }
  2059. return bRes;
  2060. }
  2061. PCCERT_CONTEXT GetPendingDummyCert(const CString& inst_name,IEnroll * pEnroll,HRESULT * phRes)
  2062. {
  2063. PCCERT_CONTEXT pRes = NULL;
  2064. HCERTSTORE hStore = OpenRequestStore(pEnroll, phRes);
  2065. if (hStore != NULL)
  2066. {
  2067. DWORD dwPropId = CERTWIZ_INSTANCE_NAME_PROP_ID;
  2068. PCCERT_CONTEXT pDummyCert = NULL;
  2069. while (NULL != (pDummyCert = CertFindCertificateInStore(hStore,
  2070. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  2071. 0, CERT_FIND_PROPERTY,
  2072. (LPVOID)&dwPropId, pDummyCert)))
  2073. {
  2074. CString str;
  2075. if (GetStringProperty(pDummyCert, dwPropId, str, phRes))
  2076. {
  2077. if (str.CompareNoCase(inst_name) == 0)
  2078. {
  2079. pRes = pDummyCert;
  2080. break;
  2081. }
  2082. }
  2083. }
  2084. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  2085. }
  2086. return pRes;
  2087. }
  2088. BOOL GetOnlineCAList(LISTCSTRING& list, const CString& certType, HRESULT * phRes)
  2089. {
  2090. BOOL bRes = TRUE;
  2091. HRESULT hr = S_OK;
  2092. DWORD errBefore = GetLastError();
  2093. DWORD dwCACount = 0;
  2094. HCAINFO hCurCAInfo = NULL;
  2095. HCAINFO hPreCAInfo = NULL;
  2096. if(certType.IsEmpty())
  2097. {
  2098. return FALSE;
  2099. }
  2100. *phRes = CAFindByCertType(certType, NULL, 0, &hCurCAInfo);
  2101. if (FAILED(*phRes) || NULL == hCurCAInfo)
  2102. {
  2103. if (S_OK == hr)
  2104. {
  2105. hr=E_FAIL;
  2106. }
  2107. return FALSE;
  2108. }
  2109. //get the CA count
  2110. if (0 == (dwCACount = CACountCAs(hCurCAInfo)))
  2111. {
  2112. *phRes = E_FAIL;
  2113. return FALSE;
  2114. }
  2115. WCHAR ** ppwstrName, ** ppwstrMachine;
  2116. while (hCurCAInfo)
  2117. {
  2118. //get the CA information
  2119. if (SUCCEEDED(CAGetCAProperty(hCurCAInfo, CA_PROP_DISPLAY_NAME, &ppwstrName))
  2120. && SUCCEEDED(CAGetCAProperty(hCurCAInfo, CA_PROP_DNSNAME, &ppwstrMachine)))
  2121. {
  2122. CString config;
  2123. config = *ppwstrMachine;
  2124. config += L"\\";
  2125. config += *ppwstrName;
  2126. //list.AddTail(config);
  2127. list.insert(list.end(),config);
  2128. CAFreeCAProperty(hCurCAInfo, ppwstrName);
  2129. CAFreeCAProperty(hCurCAInfo, ppwstrMachine);
  2130. }
  2131. else
  2132. {
  2133. bRes = FALSE;
  2134. break;
  2135. }
  2136. hPreCAInfo = hCurCAInfo;
  2137. if (FAILED(*phRes = CAEnumNextCA(hPreCAInfo, &hCurCAInfo)))
  2138. {
  2139. bRes = FALSE;
  2140. break;
  2141. }
  2142. CACloseCA(hPreCAInfo);
  2143. hPreCAInfo = NULL;
  2144. }
  2145. if (hPreCAInfo)
  2146. {
  2147. CACloseCA(hPreCAInfo);
  2148. }
  2149. if (hCurCAInfo)
  2150. {
  2151. CACloseCA(hCurCAInfo);
  2152. }
  2153. SetLastError(errBefore);
  2154. return bRes;
  2155. }
  2156. #endif