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.

446 lines
13 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: caddroot.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. // caddroot.cpp : Implementation of Ccaddroot
  11. #include "stdafx.h"
  12. #include "cobjsaf.h"
  13. #include "Xaddroot.h"
  14. #include "caddroot.h"
  15. #include "rootlist.h"
  16. #include "assert.h"
  17. #include "wincrypt.h"
  18. #include "unicode.h"
  19. #include "ui.h"
  20. BOOL FAnyCertUpdates(HCERTSTORE hStore, HCERTSTORE hStoreCertsToCheck) {
  21. BOOL fSomeNotInStore = FALSE;
  22. PCCERT_CONTEXT pCertContext = NULL;
  23. PCCERT_CONTEXT pCertTemp = NULL;
  24. BYTE arHashBytes[20];
  25. CRYPT_HASH_BLOB blobHash = {sizeof(arHashBytes), arHashBytes};
  26. while(NULL != (pCertContext = CertEnumCertificatesInStore(hStoreCertsToCheck, pCertContext))) {
  27. if( CryptHashCertificate(
  28. NULL,
  29. 0,
  30. X509_ASN_ENCODING,
  31. pCertContext->pbCertEncoded,
  32. pCertContext->cbCertEncoded,
  33. blobHash.pbData,
  34. &blobHash.cbData) ) {
  35. pCertTemp = CertFindCertificateInStore(
  36. hStore,
  37. X509_ASN_ENCODING,
  38. 0,
  39. CERT_FIND_HASH,
  40. &blobHash,
  41. NULL);
  42. fSomeNotInStore = (fSomeNotInStore || (pCertTemp == NULL));
  43. if(pCertTemp != NULL)
  44. CertFreeCertificateContext(pCertTemp);
  45. }
  46. }
  47. return(fSomeNotInStore);
  48. }
  49. BOOL MyCryptInstallSignedListOfTrustedRoots(
  50. DWORD dwMsgAndCertEncodeingType,
  51. LPCWSTR wszCTL,
  52. DWORD dwFlags,
  53. void * pvReserved
  54. ) {
  55. BOOL fIsProtected = TRUE;
  56. BOOL fRet = TRUE;
  57. DWORD cb = 0;
  58. BYTE * pb = NULL;
  59. BOOL fRemoveRoots = FALSE;
  60. HCERTSTORE hStore = NULL;
  61. HCERTSTORE hStoreRoot = NULL;
  62. PCCERT_CONTEXT pCertContext = NULL;
  63. PCCERT_CONTEXT pCertContextInStore = NULL;
  64. PCCERT_CONTEXT pCertContextSigner = NULL;
  65. HINSTANCE hCryptUI = NULL;
  66. INT_PTR iDlgRet = 0;
  67. HKEY hKeyStores = NULL;
  68. DWORD err;
  69. DWORD dwVer = 0;
  70. CRYPT_DATA_BLOB dataBlob = {0, NULL};
  71. MDI mdi;
  72. WCHAR wrgInstallCA[MAX_MSG_LEN];
  73. WCHAR wrgJustSayYes[MAX_MSG_LEN];
  74. BYTE arHashBytes[20];
  75. CRYPT_HASH_BLOB blobHash = {sizeof(arHashBytes), arHashBytes};
  76. BOOL fAnyCertUpdates;
  77. if(NULL == (pb = HTTPGet(wszCTL, &cb)))
  78. goto ErrorReturn;
  79. // get the certs to add or delete
  80. if(!I_CertVerifySignedListOfTrustedRoots(
  81. pb,
  82. cb,
  83. &fRemoveRoots,
  84. &hStore,
  85. &pCertContextSigner
  86. ))
  87. goto ErrorReturn;
  88. if(fRemoveRoots) {
  89. SetLastError(E_NOTIMPL);
  90. goto ErrorReturn;
  91. }
  92. dwVer = GetVersion();
  93. // see if this is NT5 or higher
  94. if((dwVer < 0x80000000) && ((dwVer & 0xFF) >= 5)) {
  95. if(NULL == (hStoreRoot = CertOpenStore(
  96. CERT_STORE_PROV_SYSTEM,
  97. X509_ASN_ENCODING,
  98. NULL,
  99. CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_MAXIMUM_ALLOWED_FLAG,
  100. L"Root"
  101. )) )
  102. goto ErrorReturn;
  103. // else it is before NT5 or Win9x and does not have a protected store.
  104. } else {
  105. if(ERROR_SUCCESS != (err = RegOpenKeyA(
  106. HKEY_CURRENT_USER,
  107. "Software\\Microsoft\\SystemCertificates\\Root",
  108. &hKeyStores
  109. ))) {
  110. SetLastError(err);
  111. hKeyStores = NULL;
  112. goto ErrorReturn;
  113. }
  114. // open the root store
  115. // must be current user
  116. if( NULL == (hStoreRoot = CertOpenStore(
  117. CERT_STORE_PROV_REG,
  118. X509_ASN_ENCODING,
  119. NULL,
  120. CERT_SYSTEM_STORE_CURRENT_USER,
  121. (void *) hKeyStores
  122. )) )
  123. goto ErrorReturn;
  124. fIsProtected = FALSE;
  125. }
  126. // prepare the data for the dialog
  127. memset(&mdi, 0, sizeof(mdi));
  128. if( NULL != (hCryptUI = LoadLibraryA("cryptui.dll")) )
  129. mdi.pfnCryptUIDlgViewCertificateW = (PFNCryptUIDlgViewCertificateW)
  130. GetProcAddress(hCryptUI, "CryptUIDlgViewCertificateW");
  131. mdi.hStore = hStore;
  132. mdi.pCertSigner = pCertContextSigner;
  133. mdi.hInstance = _Module.GetResourceInstance();
  134. fAnyCertUpdates = FAnyCertUpdates(hStoreRoot, hStore);
  135. if (fAnyCertUpdates) {
  136. // put the dialog up
  137. iDlgRet = DialogBoxParam(
  138. _Module.GetResourceInstance(),
  139. (LPSTR) MAKEINTRESOURCE(IDD_MAINDLG),
  140. NULL,
  141. MainDialogProc,
  142. (LPARAM) &mdi);
  143. }
  144. else
  145. {
  146. iDlgRet = IDYES;
  147. }
  148. if(hCryptUI != NULL)
  149. FreeLibrary(hCryptUI);
  150. hCryptUI = NULL;
  151. // only take it if the user said OK
  152. if(iDlgRet != IDYES)
  153. goto ErrorReturn;
  154. // throw UI if we are on a protected system
  155. if(fIsProtected && fAnyCertUpdates) {
  156. // put up the Just Say Yes to install the CA dialog
  157. LoadStringU(_Module.GetResourceInstance(), IDS_INSTALLCA, wrgInstallCA, sizeof(wrgInstallCA)/sizeof(WCHAR));
  158. LoadStringU(_Module.GetResourceInstance(), IDS_JUST_SAY_YES, wrgJustSayYes, sizeof(wrgJustSayYes)/sizeof(WCHAR));
  159. MessageBoxU(NULL, wrgJustSayYes, wrgInstallCA, MB_OK);
  160. }
  161. while(NULL != (pCertContext = CertEnumCertificatesInStore(hStore, pCertContext))) {
  162. // add the cert to the store
  163. assert(pCertContextInStore == NULL);
  164. CertAddCertificateContextToStore(
  165. hStoreRoot,
  166. pCertContext,
  167. CERT_STORE_ADD_USE_EXISTING,
  168. &pCertContextInStore
  169. );
  170. // move the EKU property in case the cert already existed
  171. if(pCertContextInStore != NULL) {
  172. assert(dataBlob.cbData == 0);
  173. // Attempt to delete the old EKU, if we succeed we will put
  174. // the new EKU on it, otherwise if we fail we know we don't
  175. // have access to HKLM and we should just add the cert to the HKCU
  176. if(!CertSetCertificateContextProperty(
  177. pCertContextInStore,
  178. CERT_ENHKEY_USAGE_PROP_ID,
  179. 0,
  180. NULL
  181. )) {
  182. // just add the cert, should go to HKCU, if it fails, what am I going
  183. // to do about it, just continue
  184. CertAddCertificateContextToStore(
  185. hStoreRoot,
  186. pCertContext,
  187. CERT_STORE_ADD_ALWAYS,
  188. NULL
  189. );
  190. // at this point I know I have access to the cert and I know the
  191. // EKU have been removed, only add the EKU if the new one has some EKU's
  192. } else if( CertGetCertificateContextProperty(
  193. pCertContext,
  194. CERT_ENHKEY_USAGE_PROP_ID,
  195. NULL,
  196. &dataBlob.cbData
  197. )
  198. &&
  199. (NULL != (dataBlob.pbData = (PBYTE) malloc(dataBlob.cbData)))
  200. &&
  201. CertGetCertificateContextProperty(
  202. pCertContext,
  203. CERT_ENHKEY_USAGE_PROP_ID,
  204. dataBlob.pbData,
  205. &dataBlob.cbData
  206. )
  207. ) {
  208. // set EKU on the cert, what am I going to do if it fails, just continue
  209. CertSetCertificateContextProperty(
  210. pCertContextInStore,
  211. CERT_ENHKEY_USAGE_PROP_ID,
  212. 0,
  213. &dataBlob
  214. );
  215. }
  216. // free context and memory
  217. CertFreeCertificateContext(pCertContextInStore);
  218. pCertContextInStore = NULL;
  219. if(dataBlob.pbData != NULL)
  220. free(dataBlob.pbData);
  221. memset(&dataBlob, 0, sizeof(CRYPT_DATA_BLOB));
  222. }
  223. }
  224. CommonReturn:
  225. if(pCertContextSigner != NULL)
  226. CertFreeCertificateContext(pCertContextSigner);
  227. if(pCertContext != NULL)
  228. CertFreeCertificateContext(pCertContext);
  229. if(pCertContextInStore != NULL)
  230. CertFreeCertificateContext(pCertContextInStore);
  231. if(hStore != NULL)
  232. CertCloseStore(hStore, CERT_CLOSE_STORE_FORCE_FLAG); // clean up from dialog box dups
  233. if(hStoreRoot != NULL)
  234. CertCloseStore(hStoreRoot, 0);
  235. if(hKeyStores != NULL)
  236. RegCloseKey(hKeyStores);
  237. if(pb != NULL)
  238. free(pb);
  239. return(fRet);
  240. ErrorReturn:
  241. fRet = FALSE;
  242. goto CommonReturn;
  243. }
  244. HRESULT STDMETHODCALLTYPE Ccaddroot::AddRoots(BSTR wszCTL) {
  245. HRESULT hr;
  246. DWORD fRet = TRUE;
  247. fRet = MyCryptInstallSignedListOfTrustedRoots(
  248. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  249. wszCTL,
  250. 0,
  251. NULL);
  252. if(fRet)
  253. hr = S_OK;
  254. else
  255. hr = MY_HRESULT_FROM_WIN32(GetLastError());
  256. return hr;
  257. }
  258. BOOL MyCryptInstallIntermediateCAs(
  259. DWORD dwMsgAndCertEncodeingType,
  260. LPCWSTR wszX509,
  261. DWORD dwFlags,
  262. void * pvReserved
  263. ) {
  264. DWORD cb = 0;
  265. DWORD cCerts = 0;
  266. BYTE * pb = NULL;
  267. PCCERT_CONTEXT pCertContext = NULL;
  268. PCCERT_CONTEXT pCertContextT = NULL;
  269. HCERTSTORE hStore = NULL;
  270. BOOL fOK = FALSE;
  271. pb = HTTPGet(wszX509, &cb);
  272. if(pb != NULL) {
  273. pCertContext = CertCreateCertificateContext(
  274. X509_ASN_ENCODING,
  275. pb,
  276. cb
  277. );
  278. if(pCertContext != NULL) {
  279. hStore = CertOpenStore(
  280. CERT_STORE_PROV_SYSTEM,
  281. X509_ASN_ENCODING,
  282. NULL,
  283. CERT_SYSTEM_STORE_CURRENT_USER,
  284. L"CA"
  285. );
  286. if(hStore != NULL) {
  287. // count the number of certs in the store
  288. cCerts = 0;
  289. while(NULL != (pCertContextT = CertEnumCertificatesInStore(hStore, pCertContextT)))
  290. cCerts++;
  291. if(FIsTooManyCertsOK(cCerts, _Module.GetResourceInstance())) {
  292. CertAddCertificateContextToStore(
  293. hStore,
  294. pCertContext,
  295. CERT_STORE_ADD_USE_EXISTING,
  296. NULL
  297. );
  298. CertCloseStore(hStore, 0);
  299. fOK = TRUE;
  300. }
  301. }
  302. CertFreeCertificateContext(pCertContext);
  303. }
  304. free(pb);
  305. }
  306. return(fOK);
  307. }
  308. HRESULT STDMETHODCALLTYPE Ccaddroot::AddCA(BSTR wszX509) {
  309. HRESULT hr;
  310. DWORD fRet = TRUE;
  311. fRet = MyCryptInstallIntermediateCAs(
  312. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  313. wszX509,
  314. 0,
  315. NULL);
  316. if(fRet)
  317. hr = S_OK;
  318. else
  319. hr = MY_HRESULT_FROM_WIN32(GetLastError());
  320. return hr;
  321. }
  322. HRESULT __stdcall Ccaddroot::GetInterfaceSafetyOptions(
  323. /* [in] */ REFIID riid,
  324. /* [out] */ DWORD __RPC_FAR *pdwSupportedOptions,
  325. /* [out] */ DWORD __RPC_FAR *pdwEnabledOptions) {
  326. RPC_STATUS rpcStatus;
  327. if(0 != UuidCompare((GUID *) &riid, (GUID *) &IID_IDispatch, &rpcStatus) )
  328. return(E_NOINTERFACE);
  329. *pdwEnabledOptions = dwEnabledSafteyOptions;
  330. *pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
  331. return(S_OK);
  332. }
  333. HRESULT __stdcall Ccaddroot::SetInterfaceSafetyOptions(
  334. /* [in] */ REFIID riid,
  335. /* [in] */ DWORD dwOptionSetMask,
  336. /* [in] */ DWORD dwEnabledOptions) {
  337. RPC_STATUS rpcStatus;
  338. DWORD dwSupport = 0;
  339. if(0 != UuidCompare((GUID *) &riid, (GUID *) &IID_IDispatch, &rpcStatus) )
  340. return(E_NOINTERFACE);
  341. dwSupport = dwOptionSetMask & ~(INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA);
  342. if(dwSupport != 0)
  343. return(E_FAIL);
  344. dwEnabledSafteyOptions &= ~dwOptionSetMask;
  345. dwEnabledSafteyOptions |= dwEnabledOptions;
  346. return(S_OK);
  347. }