Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

629 lines
15 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Copyright (c) 1997-1999 Microsoft Corporation
  4. //
  5. // File: trust.cpp
  6. //
  7. // Contents:
  8. //
  9. // History:
  10. //
  11. //---------------------------------------------------------------------------
  12. #include <windows.h>
  13. #include <wincrypt.h>
  14. #include <tchar.h>
  15. #include <stdlib.h>
  16. #include "license.h"
  17. #include "tlsapip.h"
  18. #include "trust.h"
  19. LPCTSTR g_pszServerGuid = _TEXT("d63a773e-6799-11d2-96ae-00c04fa3080d");
  20. const DWORD g_cbServerGuid = (_tcslen(g_pszServerGuid) * sizeof(TCHAR));
  21. LPCTSTR g_pszLrWizGuid = _TEXT("d46b4bf2-686d-11d2-96ae-00c04fa3080d");
  22. const DWORD g_cbLrWizGuid = (_tcslen(g_pszLrWizGuid) * sizeof(TCHAR));
  23. //----------------------------------------------------------------
  24. DWORD
  25. HashChallengeData(
  26. IN HCRYPTPROV hCryptProv,
  27. IN DWORD dwClientType,
  28. IN DWORD dwRandom,
  29. IN PBYTE pbChallengeData,
  30. IN DWORD cbChallengeData,
  31. IN PBYTE pbReserved,
  32. IN DWORD cbReserved,
  33. OUT PBYTE* ppbHashedData,
  34. OUT PDWORD pcbHashedData
  35. )
  36. /*++
  37. --*/
  38. {
  39. DWORD dwStatus = ERROR_SUCCESS;
  40. HCRYPTHASH hCryptHash = NULL;
  41. PBYTE pbHashData = NULL;
  42. DWORD cbHashData = 0;
  43. DWORD cbHashGuidSize;
  44. LPCTSTR pszHashGuid;
  45. BOOL bSuccess;
  46. //
  47. // Generate MD5 hash
  48. //
  49. bSuccess = CryptCreateHash(
  50. hCryptProv,
  51. CALG_MD5,
  52. 0,
  53. 0,
  54. &hCryptHash
  55. );
  56. if(bSuccess == FALSE)
  57. {
  58. dwStatus = GetLastError();
  59. goto cleanup;
  60. }
  61. //
  62. // Pick the right hash type
  63. //
  64. if(dwClientType == CLIENT_TYPE_LRWIZ)
  65. {
  66. pszHashGuid = g_pszLrWizGuid;
  67. cbHashGuidSize = g_cbLrWizGuid;
  68. }
  69. else
  70. {
  71. pszHashGuid = g_pszServerGuid;
  72. cbHashGuidSize = g_cbServerGuid;
  73. }
  74. //
  75. // TODO : Consider hash a few times...
  76. //
  77. bSuccess = CryptHashData(
  78. hCryptHash,
  79. (PBYTE) pbChallengeData,
  80. dwRandom,
  81. 0
  82. );
  83. if(bSuccess == FALSE)
  84. {
  85. dwStatus = GetLastError();
  86. goto cleanup;
  87. }
  88. bSuccess = CryptHashData(
  89. hCryptHash,
  90. (PBYTE) pszHashGuid,
  91. cbHashGuidSize,
  92. 0
  93. );
  94. if(bSuccess == FALSE)
  95. {
  96. dwStatus = GetLastError();
  97. goto cleanup;
  98. }
  99. bSuccess = CryptHashData(
  100. hCryptHash,
  101. (PBYTE) pbChallengeData + dwRandom,
  102. cbChallengeData - dwRandom,
  103. 0
  104. );
  105. if(bSuccess == FALSE)
  106. {
  107. dwStatus = GetLastError();
  108. goto cleanup;
  109. }
  110. //
  111. // Get the size of hased data
  112. //
  113. bSuccess = CryptGetHashParam(
  114. hCryptHash,
  115. HP_HASHVAL,
  116. NULL,
  117. &cbHashData,
  118. 0
  119. );
  120. if(bSuccess == FALSE && GetLastError() != ERROR_MORE_DATA)
  121. {
  122. dwStatus = GetLastError();
  123. goto cleanup;
  124. }
  125. pbHashData = (PBYTE)LocalAlloc(LPTR, cbHashData);
  126. if(pbHashData == NULL)
  127. {
  128. dwStatus = GetLastError();
  129. goto cleanup;
  130. }
  131. bSuccess = CryptGetHashParam(
  132. hCryptHash,
  133. HP_HASHVAL,
  134. pbHashData,
  135. &cbHashData,
  136. 0
  137. );
  138. if(bSuccess == FALSE)
  139. {
  140. dwStatus = GetLastError();
  141. }
  142. cleanup:
  143. if(hCryptHash)
  144. {
  145. CryptDestroyHash( hCryptHash );
  146. }
  147. if(dwStatus == ERROR_SUCCESS)
  148. {
  149. *ppbHashedData = pbHashData;
  150. *pcbHashedData = cbHashData;
  151. pbHashData = NULL;
  152. }
  153. if(pbHashData != NULL)
  154. {
  155. LocalFree(pbHashData);
  156. }
  157. return dwStatus;
  158. }
  159. //----------------------------------------------------------------
  160. DWORD WINAPI
  161. TLSVerifyChallengeResponse(
  162. IN HCRYPTPROV hCryptProv,
  163. IN DWORD dwClientType,
  164. IN PTLSCHALLENGEDATA pClientChallengeData,
  165. IN PTLSCHALLENGERESPONSEDATA pServerChallengeResponseData
  166. )
  167. /*++
  168. --*/
  169. {
  170. DWORD dwStatus = ERROR_SUCCESS;
  171. PBYTE pbData = NULL;
  172. DWORD cbData = 0;
  173. //
  174. // base on our challenge data, generate a corresponding
  175. // hash data
  176. //
  177. dwStatus = HashChallengeData(
  178. hCryptProv,
  179. dwClientType,
  180. pClientChallengeData->dwRandom,
  181. pClientChallengeData->pbChallengeData,
  182. pClientChallengeData->cbChallengeData,
  183. pClientChallengeData->pbReservedData,
  184. pClientChallengeData->cbReservedData,
  185. &pbData,
  186. &cbData
  187. );
  188. if(dwStatus != ERROR_SUCCESS)
  189. {
  190. goto cleanup;
  191. }
  192. //
  193. // Compare our hash with response data
  194. //
  195. if(pServerChallengeResponseData->cbResponseData != cbData)
  196. {
  197. dwStatus = ERROR_INVALID_DATA;
  198. }
  199. if(memcmp(pServerChallengeResponseData->pbResponseData, pbData, cbData) != 0)
  200. {
  201. dwStatus = ERROR_INVALID_DATA;
  202. }
  203. cleanup:
  204. if(pbData != NULL)
  205. LocalFree(pbData);
  206. return dwStatus;
  207. }
  208. //----------------------------------------------------------------
  209. DWORD
  210. TLSGenerateChallengeResponseData(
  211. IN HCRYPTPROV hCryptProv,
  212. IN DWORD dwClientType,
  213. IN PTLSCHALLENGEDATA pChallengeData,
  214. OUT PBYTE* pbResponseData,
  215. OUT PDWORD cbResponseData
  216. )
  217. /*++
  218. --*/
  219. {
  220. DWORD dwStatus = ERROR_SUCCESS;
  221. dwStatus = HashChallengeData(
  222. hCryptProv,
  223. dwClientType,
  224. pChallengeData->dwRandom,
  225. pChallengeData->pbChallengeData,
  226. pChallengeData->cbChallengeData,
  227. pChallengeData->pbReservedData,
  228. pChallengeData->cbReservedData,
  229. pbResponseData,
  230. cbResponseData
  231. );
  232. return dwStatus;
  233. }
  234. //----------------------------------------------------------------
  235. DWORD WINAPI
  236. TLSGenerateRandomChallengeData(
  237. IN HCRYPTPROV hCryptProv,
  238. IN PBYTE* ppbChallengeData,
  239. IN PDWORD pcbChallengeData
  240. )
  241. /*++
  242. Abstract:
  243. Generate two random 128 bit challenge data and concatenate it
  244. before returning.
  245. Parameters:
  246. hCryptProv : Crypto. provider.
  247. pcbChallengeData : Pointer to DWORD receiving size
  248. of challenge data.
  249. ppbChallengeData : Pointer to BYTE receiving randomly
  250. generated challege data.
  251. Returns:
  252. ERROR_SUCCESS or error code.
  253. Note:
  254. All memory allocation via LocalAlloc().
  255. --*/
  256. {
  257. DWORD dwLen = RANDOM_CHALLENGE_DATASIZE;
  258. DWORD dwStatus = ERROR_SUCCESS;
  259. BOOL bSuccess;
  260. PBYTE pbRandomData = NULL;
  261. if( ppbChallengeData == NULL ||
  262. pcbChallengeData == NULL ||
  263. hCryptProv == NULL )
  264. {
  265. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  266. goto cleanup;
  267. }
  268. pbRandomData = (PBYTE)LocalAlloc(LPTR, dwLen * 2);
  269. if(pbRandomData == NULL)
  270. {
  271. dwStatus = GetLastError();
  272. goto cleanup;
  273. }
  274. //
  275. // generate two random 128 bit data
  276. //
  277. bSuccess = CryptGenRandom(
  278. hCryptProv,
  279. dwLen,
  280. pbRandomData
  281. );
  282. if(bSuccess == TRUE)
  283. {
  284. memcpy(
  285. pbRandomData + dwLen,
  286. pbRandomData,
  287. dwLen
  288. );
  289. bSuccess = CryptGenRandom(
  290. hCryptProv,
  291. dwLen,
  292. pbRandomData + dwLen
  293. );
  294. }
  295. if(bSuccess == FALSE)
  296. {
  297. dwStatus = GetLastError();
  298. }
  299. cleanup:
  300. if(dwStatus == ERROR_SUCCESS)
  301. {
  302. *ppbChallengeData = pbRandomData;
  303. *pcbChallengeData = dwLen * 2;
  304. }
  305. else
  306. {
  307. if(pbRandomData != NULL)
  308. {
  309. LocalFree(pbRandomData);
  310. }
  311. }
  312. return dwStatus;
  313. }
  314. //----------------------------------------------------------------
  315. DWORD WINAPI
  316. TLSEstablishTrustWithServer(
  317. IN TLS_HANDLE hHandle,
  318. IN HCRYPTPROV hCryptProv,
  319. IN DWORD dwClientType,
  320. OUT PDWORD pdwErrCode
  321. )
  322. /*++
  323. Abstract:
  324. Establish trust relationship with License Server, trust is
  325. based on two way challenge/response. License Server and LrWiz
  326. can't use certificate-base trust verification as anyone can get
  327. TermSrv certificate from registry and also be the administrator
  328. of system to invoke server side administrative RPC call to mess
  329. up license server setup. This challenge/response scheme should be
  330. kept secret (user can reverse engineer to figure out our algorithm
  331. but this user probably smart enough to alter executable to return
  332. SUCCESS in all case too.)
  333. Parameters:
  334. hHandle : Connection handle to License Server.
  335. hCryptProv : handle to CSP to do hashing.
  336. dwClientType : Caller type, License Server, LrWiz, or TermSrv.
  337. pdwErrCode : Pointer to DWORD to receive License Server return code.
  338. Return:
  339. ERROR_SUCCESS or RPC error code. Caller should also verify pdwErrCode.
  340. Note:
  341. TermSrv's certificate is issued by license server.
  342. --*/
  343. {
  344. DWORD dwStatus = ERROR_SUCCESS;
  345. PBYTE pbClientRandomChallengeData = NULL;
  346. DWORD cbClientRandomChallengeData = 0;
  347. PBYTE pbChallengeResponseData = NULL;
  348. DWORD cbChallengeResponseData = 0;
  349. TLSCHALLENGEDATA ClientChallengeData;
  350. TLSCHALLENGERESPONSEDATA* pServerChallengeResponseData=NULL;
  351. TLSCHALLENGEDATA* pServerChallengeData=NULL;
  352. TLSCHALLENGERESPONSEDATA ClientChallengeResponseData;
  353. //
  354. // Verify input parameters
  355. //
  356. if(hHandle == NULL || hCryptProv == NULL)
  357. {
  358. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  359. goto cleanup;
  360. }
  361. //
  362. // Only three type supported
  363. //
  364. if( dwClientType != CLIENT_TYPE_TLSERVER &&
  365. dwClientType != CLIENT_TYPE_LRWIZ &&
  366. dwClientType != CLIENT_TYPE_TERMSRV )
  367. {
  368. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  369. goto cleanup;
  370. }
  371. //
  372. // Generate a random challenge data
  373. //
  374. dwStatus = TLSGenerateRandomChallengeData(
  375. hCryptProv,
  376. &pbClientRandomChallengeData,
  377. &cbClientRandomChallengeData
  378. );
  379. if(dwStatus != ERROR_SUCCESS)
  380. {
  381. goto cleanup;
  382. }
  383. //
  384. //
  385. //
  386. memset(
  387. &ClientChallengeData,
  388. 0,
  389. sizeof(TLSCHALLENGEDATA)
  390. );
  391. memset(
  392. &ClientChallengeResponseData,
  393. 0,
  394. sizeof(TLSCHALLENGERESPONSEDATA)
  395. );
  396. //
  397. // Send this challenge data to server
  398. //
  399. ClientChallengeData.dwVersion = TLS_CURRENT_CHALLENGE_VERSION;
  400. if (!CryptGenRandom(hCryptProv,sizeof(ClientChallengeData.dwRandom), (BYTE *)&(ClientChallengeData.dwRandom))) {
  401. dwStatus = GetLastError();
  402. goto cleanup;
  403. }
  404. //
  405. // This must range from 1 to 128, as it's used as an offset into the
  406. // challenge data buffer
  407. //
  408. ClientChallengeData.dwRandom %= RANDOM_CHALLENGE_DATASIZE;
  409. ClientChallengeData.dwRandom++;
  410. ClientChallengeData.cbChallengeData = cbClientRandomChallengeData;
  411. ClientChallengeData.pbChallengeData = pbClientRandomChallengeData;
  412. dwStatus = TLSChallengeServer(
  413. hHandle,
  414. dwClientType,
  415. &ClientChallengeData,
  416. &pServerChallengeResponseData,
  417. &pServerChallengeData,
  418. pdwErrCode
  419. );
  420. if(dwStatus != RPC_S_OK || *pdwErrCode >= LSERVER_ERROR_BASE)
  421. {
  422. goto cleanup;
  423. }
  424. if(pServerChallengeResponseData == NULL || pServerChallengeData == NULL)
  425. {
  426. dwStatus = LSERVER_E_INTERNAL_ERROR;
  427. goto cleanup;
  428. }
  429. //
  430. // Verify Server Challege Data.
  431. //
  432. dwStatus = TLSVerifyChallengeResponse(
  433. hCryptProv,
  434. dwClientType,
  435. &ClientChallengeData,
  436. pServerChallengeResponseData
  437. );
  438. if(dwStatus != ERROR_SUCCESS)
  439. {
  440. goto cleanup;
  441. }
  442. //
  443. // Generate Client side responses data
  444. //
  445. dwStatus = TLSGenerateChallengeResponseData(
  446. hCryptProv,
  447. dwClientType,
  448. pServerChallengeData,
  449. &pbChallengeResponseData,
  450. &cbChallengeResponseData
  451. );
  452. if(dwStatus != ERROR_SUCCESS)
  453. {
  454. goto cleanup;
  455. }
  456. //
  457. // Response to server's challenge
  458. //
  459. ClientChallengeResponseData.dwVersion = TLS_CURRENT_CHALLENGE_VERSION;
  460. ClientChallengeResponseData.cbResponseData = cbChallengeResponseData;
  461. ClientChallengeResponseData.pbResponseData = pbChallengeResponseData;
  462. dwStatus = TLSResponseServerChallenge(
  463. hHandle,
  464. &ClientChallengeResponseData,
  465. pdwErrCode
  466. );
  467. cleanup:
  468. //
  469. // Cleanup memory allocated.
  470. //
  471. if(pbClientRandomChallengeData != NULL)
  472. {
  473. LocalFree(pbClientRandomChallengeData);
  474. }
  475. if(pbChallengeResponseData != NULL)
  476. {
  477. LocalFree(pbChallengeResponseData);
  478. }
  479. if(pServerChallengeData != NULL)
  480. {
  481. if(pServerChallengeData->pbChallengeData)
  482. {
  483. midl_user_free(pServerChallengeData->pbChallengeData);
  484. }
  485. if(pServerChallengeData->pbReservedData)
  486. {
  487. midl_user_free(pServerChallengeData->pbReservedData);
  488. }
  489. midl_user_free(pServerChallengeData);
  490. }
  491. if(pServerChallengeResponseData != NULL)
  492. {
  493. if(pServerChallengeResponseData->pbResponseData)
  494. {
  495. midl_user_free(pServerChallengeResponseData->pbResponseData);
  496. }
  497. if(pServerChallengeResponseData->pbReservedData)
  498. {
  499. midl_user_free(pServerChallengeResponseData->pbReservedData);
  500. }
  501. midl_user_free(pServerChallengeResponseData);
  502. }
  503. return dwStatus;
  504. }