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.

555 lines
14 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1995 - 1996
  6. //
  7. // File: updcrl.cpp
  8. //
  9. // Contents: Updates CRL in the "CA" store.
  10. //
  11. // See Usage() for list of options.
  12. //
  13. //
  14. // Functions: main
  15. //
  16. // History: 30-Aug-00 philh created
  17. //
  18. //--------------------------------------------------------------------------
  19. #include <windows.h>
  20. #include "wincrypt.h"
  21. #include "wintrust.h"
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <memory.h>
  26. #include <time.h>
  27. void PrintLastError(LPCSTR pszMsg)
  28. {
  29. DWORD dwErr = GetLastError();
  30. char buf[512];
  31. sprintf(buf, "%s failed => 0x%x (%d) \n", pszMsg, dwErr, dwErr);
  32. MessageBoxA(
  33. NULL, // hWnd
  34. buf,
  35. "UpdCrl",
  36. MB_OK | MB_ICONERROR | MB_TASKMODAL
  37. );
  38. }
  39. void PrintMsg(LPCSTR pszMsg)
  40. {
  41. MessageBoxA(
  42. NULL, // hWnd
  43. pszMsg,
  44. "UpdCrl",
  45. MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL
  46. );
  47. }
  48. static void Usage(void)
  49. {
  50. MessageBoxA(
  51. NULL, // hWnd
  52. "Usage: UpdCrl [options] <SrcCrlFilename>\n"
  53. "Options are:\n"
  54. "-h -\tThis message\n"
  55. "-r -\tRegister NoCDPCRLRevocationChecking\n"
  56. "-e -\tEnable revocation checking\n"
  57. "-d -\tDisable revocation checking\n"
  58. "-u -\tUser\n"
  59. "\n",
  60. "UpdCrl",
  61. MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL
  62. );
  63. }
  64. BOOL
  65. IsLogicalStoreSupported()
  66. {
  67. HMODULE hModule;
  68. hModule = GetModuleHandleA("crypt32.dll");
  69. if (NULL == hModule)
  70. return FALSE;
  71. if (NULL == GetProcAddress(hModule, "CertEnumPhysicalStore"))
  72. return FALSE;
  73. return TRUE;
  74. }
  75. void
  76. UpdateRevocation(
  77. IN BOOL fEnable
  78. )
  79. {
  80. HKEY hKey = NULL;
  81. DWORD dwState;
  82. DWORD cbData;
  83. DWORD dwType;
  84. DWORD dwDisposition;
  85. // Open the registry and get to the "State" REG_DWORD value
  86. if (ERROR_SUCCESS != RegCreateKeyExA(
  87. HKEY_CURRENT_USER,
  88. "Software\\Microsoft\\Windows\\CurrentVersion\\WinTrust\\Trust Providers\\Software Publishing",
  89. 0,
  90. NULL,
  91. REG_OPTION_NON_VOLATILE,
  92. KEY_ALL_ACCESS,
  93. NULL,
  94. &hKey,
  95. &dwDisposition
  96. ))
  97. return;
  98. dwState = 0;
  99. cbData = sizeof(dwState);
  100. if (ERROR_SUCCESS != RegQueryValueExA(
  101. hKey,
  102. "State",
  103. NULL,
  104. &dwType,
  105. (BYTE *) &dwState,
  106. &cbData
  107. ) || sizeof(dwState) != cbData || REG_DWORD != dwType)
  108. dwState = WTPF_IGNOREREVOCATIONONTS;
  109. if (fEnable) {
  110. dwState &= ~WTPF_IGNOREREVOKATION;
  111. dwState |=
  112. WTPF_OFFLINEOK_IND |
  113. WTPF_OFFLINEOK_COM |
  114. WTPF_OFFLINEOKNBU_IND |
  115. WTPF_OFFLINEOKNBU_COM
  116. ;
  117. } else
  118. dwState |= WTPF_IGNOREREVOKATION;
  119. RegSetValueExA(
  120. hKey,
  121. "State",
  122. 0, // dwReserved
  123. REG_DWORD,
  124. (BYTE *) &dwState,
  125. sizeof(dwState)
  126. );
  127. RegCloseKey(hKey);
  128. }
  129. PCCRL_CONTEXT
  130. OpenCrlFile(
  131. IN LPSTR pszCrlFilename
  132. )
  133. {
  134. PCCRL_CONTEXT pCrl = NULL;
  135. HANDLE hFile = NULL;
  136. BYTE *pbEncoded = NULL;
  137. DWORD cbEncoded;
  138. DWORD cbRead;
  139. DWORD dwErr = 0;
  140. if (INVALID_HANDLE_VALUE == (hFile = CreateFile(
  141. pszCrlFilename,
  142. GENERIC_READ,
  143. FILE_SHARE_READ | FILE_SHARE_WRITE,
  144. NULL,
  145. OPEN_EXISTING,
  146. 0,
  147. NULL)))
  148. return NULL;
  149. cbEncoded = GetFileSize(hFile, NULL);
  150. if (0 == cbEncoded)
  151. goto EmptyFileError;
  152. if (NULL == (pbEncoded = (BYTE *) LocalAlloc(LPTR, cbEncoded)))
  153. goto OutOfMemory;
  154. if (!ReadFile(hFile, pbEncoded, cbEncoded, &cbRead, NULL) ||
  155. (cbRead != cbEncoded))
  156. goto ReadFileError;
  157. pCrl = CertCreateCRLContext(
  158. X509_ASN_ENCODING,
  159. pbEncoded,
  160. cbEncoded
  161. );
  162. CommonReturn:
  163. dwErr = GetLastError();
  164. if (hFile)
  165. CloseHandle(hFile);
  166. if (pbEncoded)
  167. LocalFree(pbEncoded);
  168. SetLastError(dwErr);
  169. return pCrl;
  170. ErrorReturn:
  171. goto CommonReturn;
  172. EmptyFileError:
  173. SetLastError(ERROR_INVALID_DATA);
  174. goto ErrorReturn;
  175. OutOfMemory:
  176. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  177. goto ErrorReturn;
  178. ReadFileError:
  179. goto ErrorReturn;
  180. }
  181. #if 0
  182. // In W2K, the NOCDP CRL needs to be time valid.
  183. BOOL
  184. IsNoCDPCRLSupported()
  185. {
  186. HMODULE hModule;
  187. hModule = GetModuleHandleA("crypt32.dll");
  188. if (NULL == hModule)
  189. return FALSE;
  190. // "CryptVerifyCertificateSignatureEx" added in W2K, WinME and CMS
  191. if (NULL == GetProcAddress(hModule, "CertIsValidCRLForCertificate"))
  192. return FALSE;
  193. return TRUE;
  194. }
  195. #endif
  196. BOOL
  197. FIsWinNT5()
  198. {
  199. BOOL fIsWinNT5 = FALSE;
  200. OSVERSIONINFO osVer;
  201. memset(&osVer, 0, sizeof(OSVERSIONINFO));
  202. osVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  203. if (GetVersionEx(&osVer)) {
  204. BOOL fIsWinNT;
  205. fIsWinNT = (osVer.dwPlatformId == VER_PLATFORM_WIN32_NT);
  206. if (!fIsWinNT) {
  207. return FALSE;
  208. }
  209. fIsWinNT5 = ( osVer.dwMajorVersion >= 5 );
  210. }
  211. return fIsWinNT5;
  212. }
  213. //+-------------------------------------------------------------------------
  214. // Get file version of the specified file
  215. //--------------------------------------------------------------------------
  216. BOOL
  217. WINAPI
  218. I_GetFileVersion(
  219. IN LPCSTR pszFilename,
  220. OUT DWORD *pdwFileVersionMS, /* e.g. 0x00030075 = "3.75" */
  221. OUT DWORD *pdwFileVersionLS /* e.g. 0x00000031 = "0.31" */
  222. )
  223. {
  224. BOOL fResult;
  225. DWORD dwHandle = 0;
  226. DWORD cbInfo;
  227. void *pvInfo = NULL;
  228. VS_FIXEDFILEINFO *pFixedFileInfo = NULL; // not allocated
  229. UINT ccFixedFileInfo = 0;
  230. if (0 == (cbInfo = GetFileVersionInfoSizeA((LPSTR) pszFilename, &dwHandle)))
  231. goto GetFileVersionInfoSizeError;
  232. if (NULL == (pvInfo = LocalAlloc(LPTR, cbInfo)))
  233. goto OutOfMemory;
  234. if (!GetFileVersionInfoA(
  235. (LPSTR) pszFilename,
  236. 0, // dwHandle, ignored
  237. cbInfo,
  238. pvInfo
  239. ))
  240. goto GetFileVersionInfoError;
  241. if (!VerQueryValueA(
  242. pvInfo,
  243. "\\", // VS_FIXEDFILEINFO
  244. (void **) &pFixedFileInfo,
  245. &ccFixedFileInfo
  246. ))
  247. goto VerQueryValueError;
  248. *pdwFileVersionMS = pFixedFileInfo->dwFileVersionMS;
  249. *pdwFileVersionLS = pFixedFileInfo->dwFileVersionLS;
  250. fResult = TRUE;
  251. CommonReturn:
  252. if (pvInfo)
  253. LocalFree(pvInfo);
  254. return fResult;
  255. OutOfMemory:
  256. GetFileVersionInfoSizeError:
  257. GetFileVersionInfoError:
  258. VerQueryValueError:
  259. *pdwFileVersionMS = 0;
  260. *pdwFileVersionLS = 0;
  261. fResult = FALSE;
  262. goto CommonReturn;
  263. }
  264. void
  265. RegisterNoCDPCRLRevocationChecking()
  266. {
  267. CHAR szSystemDir[MAX_PATH + 32];
  268. UINT cch;
  269. // Just in case, unregister vsrevoke.dll
  270. CryptUnregisterDefaultOIDFunction(
  271. X509_ASN_ENCODING,
  272. CRYPT_OID_VERIFY_REVOCATION_FUNC,
  273. L"vsrevoke.dll"
  274. );
  275. // For W2K and beyond, won't be installing mscrlrev.dll
  276. if (FIsWinNT5()) {
  277. // For upgrades, unregister legacy versions
  278. CryptUnregisterDefaultOIDFunction(
  279. X509_ASN_ENCODING,
  280. CRYPT_OID_VERIFY_REVOCATION_FUNC,
  281. L"mscrlrev.dll"
  282. );
  283. return;
  284. }
  285. // Need to copy mscrlrev.dll to system32
  286. cch = GetSystemDirectory(szSystemDir, MAX_PATH - 1);
  287. if (0 == cch || MAX_PATH <= cch) {
  288. PrintLastError("GetSystemDirectory");
  289. return;
  290. }
  291. strcpy(&szSystemDir[cch], "\\mscrlrev.dll");
  292. // On the first copy, only succeed if the file doesn't already exist
  293. if (!CopyFileA("mscrlrev.dll", szSystemDir, TRUE)) {
  294. DWORD dwOldFileVersionMS = 0;
  295. DWORD dwOldFileVersionLS = 0;
  296. DWORD dwNewFileVersionMS = 0;
  297. DWORD dwNewFileVersionLS = 0;
  298. // Determine if we have a newer mscrlrev.dll to be installed
  299. I_GetFileVersion(szSystemDir,
  300. &dwOldFileVersionMS, &dwOldFileVersionLS);
  301. I_GetFileVersion("mscrlrev.dll",
  302. &dwNewFileVersionMS, &dwNewFileVersionLS);
  303. if (dwNewFileVersionMS > dwOldFileVersionMS
  304. ||
  305. (dwNewFileVersionMS == dwOldFileVersionMS &&
  306. dwNewFileVersionLS > dwOldFileVersionLS)) {
  307. // We have a newer version
  308. SetFileAttributesA(szSystemDir, FILE_ATTRIBUTE_NORMAL);
  309. // Copy over the existing file
  310. if (!CopyFileA("mscrlrev.dll", szSystemDir, FALSE)) {
  311. DWORD dwLastErr;
  312. dwLastErr = GetLastError();
  313. if (ERROR_ACCESS_DENIED != dwLastErr)
  314. PrintLastError("CopyFile(mscrlrev.dll)");
  315. }
  316. }
  317. }
  318. // Need to register mscrlrev.dll
  319. if (!CryptRegisterDefaultOIDFunction(
  320. X509_ASN_ENCODING,
  321. CRYPT_OID_VERIFY_REVOCATION_FUNC,
  322. CRYPT_REGISTER_FIRST_INDEX,
  323. L"mscrlrev.dll"
  324. )) {
  325. if (ERROR_FILE_EXISTS != GetLastError())
  326. PrintLastError("Register mscrlrev.dll");
  327. }
  328. }
  329. #define MAX_CRL_FILE_CNT 32
  330. int _cdecl main(int argc, char * argv[])
  331. {
  332. BOOL fResult;
  333. int ReturnStatus = 0;
  334. LPSTR rgpszCrlFilename[MAX_CRL_FILE_CNT]; // not allocated
  335. DWORD cCrlFilename = 0;
  336. HCERTSTORE hCAStore = NULL;
  337. BOOL fUser = FALSE;
  338. BOOL fLogicalStoreSupported = FALSE;
  339. DWORD i;
  340. while (--argc>0)
  341. {
  342. if (**++argv == '-')
  343. {
  344. switch(argv[0][1])
  345. {
  346. case 'e':
  347. UpdateRevocation(TRUE);
  348. break;
  349. case 'd':
  350. UpdateRevocation(FALSE);
  351. break;
  352. case 'r':
  353. RegisterNoCDPCRLRevocationChecking();
  354. break;
  355. case 'u':
  356. fUser = TRUE;
  357. break;
  358. case 'h':
  359. default:
  360. goto BadUsage;
  361. }
  362. } else {
  363. if (MAX_CRL_FILE_CNT > cCrlFilename)
  364. rgpszCrlFilename[cCrlFilename++] = argv[0];
  365. else {
  366. PrintMsg("Too many Crl filenames\n");
  367. goto BadUsage;
  368. }
  369. }
  370. }
  371. if (0 == cCrlFilename)
  372. goto SuccessReturn;
  373. fLogicalStoreSupported = IsLogicalStoreSupported();
  374. if (fUser && fLogicalStoreSupported)
  375. // Already installed in HKLM
  376. goto SuccessReturn;
  377. // Attempt to open the destination CA store.
  378. // For earlier versions not supporting logical stores, its the
  379. // HKCU "CA" store. Otherwise, its the HKLM "CA" store.
  380. hCAStore = CertOpenStore(
  381. CERT_STORE_PROV_SYSTEM_A,
  382. 0, // dwEncodingType
  383. 0, // hCryptProv
  384. fLogicalStoreSupported ?
  385. CERT_SYSTEM_STORE_LOCAL_MACHINE : CERT_SYSTEM_STORE_CURRENT_USER,
  386. (const void *) "CA"
  387. );
  388. if (NULL == hCAStore) {
  389. PrintLastError("Open CAStore");
  390. goto ErrorReturn;
  391. }
  392. for (i = 0; i < cCrlFilename; i++) {
  393. PCCRL_CONTEXT pCrl;
  394. // Attempt to open the Crl file
  395. pCrl = OpenCrlFile(rgpszCrlFilename[i]);
  396. if (NULL == pCrl) {
  397. PrintLastError("Open CrlFile");
  398. goto ErrorReturn;
  399. }
  400. fResult = CertAddCRLContextToStore(
  401. hCAStore,
  402. pCrl,
  403. CERT_STORE_ADD_NEWER,
  404. NULL
  405. );
  406. if (!fResult && CRYPT_E_EXISTS != GetLastError()) {
  407. // Note, earlier versions of crypt32.dll didn't support
  408. // CERT_STORE_ADD_NEWER
  409. // Will need to see if the CRL already exists in the store
  410. // and do our comparison.
  411. PCCRL_CONTEXT pExistingCrl = NULL;
  412. DWORD dwGetFlags = 0;
  413. while (pExistingCrl = CertGetCRLFromStore(
  414. hCAStore,
  415. NULL, // pIssuerContext
  416. pExistingCrl,
  417. &dwGetFlags
  418. )) {
  419. dwGetFlags = 0;
  420. // See if it has the same issuer name
  421. if (pExistingCrl->dwCertEncodingType !=
  422. pCrl->dwCertEncodingType
  423. ||
  424. !CertCompareCertificateName(
  425. pCrl->dwCertEncodingType,
  426. &pCrl->pCrlInfo->Issuer,
  427. &pExistingCrl->pCrlInfo->Issuer
  428. ))
  429. continue;
  430. // See if the existing is newer
  431. // CompareFileTime returns 0 if the same and
  432. // +1 if first time > second time
  433. if (0 <= CompareFileTime(
  434. &pExistingCrl->pCrlInfo->ThisUpdate,
  435. &pCrl->pCrlInfo->ThisUpdate
  436. ))
  437. break;
  438. }
  439. if (pExistingCrl)
  440. CertFreeCRLContext(pExistingCrl);
  441. else {
  442. fResult = CertAddCRLContextToStore(
  443. hCAStore,
  444. pCrl,
  445. CERT_STORE_ADD_REPLACE_EXISTING,
  446. NULL
  447. );
  448. if (!fResult)
  449. PrintLastError("AddCRL");
  450. }
  451. }
  452. CertFreeCRLContext(pCrl);
  453. if (!fResult)
  454. goto ErrorReturn;
  455. }
  456. SuccessReturn:
  457. ReturnStatus = 0;
  458. CommonReturn:
  459. if (hCAStore)
  460. CertCloseStore(hCAStore, 0);
  461. return ReturnStatus;
  462. BadUsage:
  463. Usage();
  464. ErrorReturn:
  465. ReturnStatus = -1;
  466. goto CommonReturn;
  467. }