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.

600 lines
17 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 2000
  6. //
  7. // File: nonce.cxx
  8. //
  9. // Contents: Context APIs for the Digest security package
  10. // Main entry points into this dll:
  11. // NonceCreate
  12. // NonceValidate
  13. // NonceInitialize
  14. //
  15. // History: ChandanS 26-Jul-1996 Stolen from kerberos\client2\ctxtapi.cxx
  16. // KDamour 16Mar00 Stolen from NTLM ctxtapi.cxx
  17. //
  18. //------------------------------------------------------------------------
  19. #include <global.h>
  20. #include <time.h>
  21. // Hold the Hex representation plus the NULL
  22. char g_cNoncePrivateKey[(2*NONCE_PRIVATE_KEY_BYTESIZE) + 1];
  23. //
  24. // Globals
  25. //
  26. HCRYPTPROV g_hCryptProv = 0; // Handle for CryptoAPI
  27. WORD g_SupportedCrypto = 0; // Supported Crypt Functions bitmask (i.e. SUPPORT_DES)
  28. //+--------------------------------------------------------------------
  29. //
  30. // Function: NonceInitialize
  31. //
  32. // Synopsis: This function is to be called
  33. //
  34. // Arguments: None
  35. //
  36. // Returns:
  37. //
  38. // Notes:
  39. // CryptReleaseContext( g_hCryptProv, 0 ) to release the cypt context
  40. //
  41. //---------------------------------------------------------------------
  42. NTSTATUS NTAPI
  43. NonceInitialize(
  44. VOID
  45. )
  46. {
  47. NTSTATUS Status = STATUS_SUCCESS;
  48. BYTE abTemp[NONCE_PRIVATE_KEY_BYTESIZE];
  49. DebugLog((DEB_TRACE_FUNC, "NonceInitialize: Entering\n"));
  50. if (g_hCryptProv)
  51. { // Catch cases where LSA and Usermode running in same addr space
  52. DebugLog((DEB_TRACE, "NonceInitialize: Already Inited Leaving\n"));
  53. return STATUS_SUCCESS;
  54. }
  55. //
  56. // Get a handle to the CSP we'll use for all our hash functions etc
  57. //
  58. if ( !CryptAcquireContext( &g_hCryptProv,
  59. NULL,
  60. NULL,
  61. PROV_RSA_FULL,
  62. CRYPT_VERIFYCONTEXT ) )
  63. {
  64. DebugLog((DEB_ERROR, "NonceInitialize:CryptCreateHash() failed : 0x%lx\n", GetLastError()));
  65. Status = STATUS_INTERNAL_ERROR;
  66. return(Status);
  67. }
  68. //
  69. // Generate and copy over the random bytes
  70. //
  71. if ( !CryptGenRandom( g_hCryptProv,
  72. NONCE_PRIVATE_KEY_BYTESIZE,
  73. abTemp ) )
  74. {
  75. DebugLog((DEB_ERROR, "NonceInitialize:NonceInitialize CryptGenRandom() failed : 0x%lx\n", GetLastError()));
  76. Status = STATUS_INTERNAL_ERROR;
  77. return (Status);
  78. }
  79. BinToHex((LPBYTE) abTemp, NONCE_PRIVATE_KEY_BYTESIZE, (LPSTR) g_cNoncePrivateKey);
  80. SetSupportedCrypto();
  81. DebugLog((DEB_TRACE_FUNC, "NonceInitialize:Leaving NonceInitialize\n"));
  82. return (Status);
  83. }
  84. //+--------------------------------------------------------------------
  85. //
  86. // Function: SetSupportedCrypto
  87. //
  88. // Synopsis: Set the bitmask for the supported crypto CSP installed
  89. //
  90. // Arguments: none
  91. //
  92. // Returns: STATUS_DATA_ERROR - error in reading CSP capabilities
  93. // STATUS_SUCCESS - operation completed normally
  94. //
  95. //
  96. //---------------------------------------------------------------------
  97. NTSTATUS NTAPI
  98. SetSupportedCrypto(VOID)
  99. {
  100. NTSTATUS Status = STATUS_SUCCESS;
  101. g_SupportedCrypto = SUPPORT_3DES | SUPPORT_DES | SUPPORT_RC4_40 | SUPPORT_RC4 | SUPPORT_RC4_56;
  102. // FIXFIX use CryptGetProvParam to set to actual installed CSP
  103. return(Status);
  104. }
  105. //+--------------------------------------------------------------------
  106. //
  107. // Function: NonceCreate
  108. //
  109. // Synopsis: This function is to be called once during User Mode initialization
  110. //
  111. // Arguments: pczNonce - pointer to a STRING to fillin
  112. // with a new nonce
  113. //
  114. // Returns: STATUS_DATA_ERROR - input NONCE not enough space
  115. // STATUS_SUCCESS - operation completed normally
  116. //
  117. // Notes: Function will return error if Nonce UNICODE_STRING is not empty
  118. // NONCE FORMAT
  119. // rand-data = rand[16]
  120. // nonce_binary = time-stamp rand-data H(time-stamp ":" rand-data ":" nonce_private_key)
  121. // nonce = hex(nonce_binary)
  122. //
  123. //---------------------------------------------------------------------
  124. NTSTATUS NTAPI
  125. NonceCreate(
  126. IN OUT PSTRING pstrNonce
  127. )
  128. {
  129. NTSTATUS Status = STATUS_SUCCESS;
  130. BYTE abRandomData[RANDDATA_BYTESIZE];
  131. char acRandomHex[(2*RANDDATA_BYTESIZE) + 1];
  132. FILETIME tcurrent = {0};
  133. GetSystemTimeAsFileTime(&tcurrent);
  134. DebugLog((DEB_TRACE_FUNC, "NonceCreate: Entering\n"));
  135. // Check to make sure that there is enough space on ouput string
  136. // Need room for the Nonce and the NULL terminator
  137. if (!pstrNonce->Buffer)
  138. {
  139. Status = StringAllocate(pstrNonce, NONCE_SIZE);
  140. if (!NT_SUCCESS (Status))
  141. {
  142. Status = SEC_E_INSUFFICIENT_MEMORY;
  143. DebugLog((DEB_ERROR, "NonceCreate: StringAllocate error 0x%x\n", Status));
  144. goto CleanUp;
  145. }
  146. }
  147. if (pstrNonce->MaximumLength < (NONCE_SIZE + 1))
  148. {
  149. DebugLog((DEB_ERROR, "NonceCreate: Input STRING too small\n"));
  150. Status = STATUS_BUFFER_TOO_SMALL;
  151. goto CleanUp;
  152. }
  153. // Copy over the current time
  154. BinToHex((LPBYTE)&tcurrent, sizeof(tcurrent), (LPSTR) pstrNonce->Buffer);
  155. //
  156. // Generate and copy over the random bytes
  157. //
  158. if ( !CryptGenRandom( g_hCryptProv,
  159. RANDDATA_BYTESIZE,
  160. abRandomData ) )
  161. {
  162. DebugLog((DEB_TRACE, "NonceCreate: CryptGenRandom() failed : 0x%x\n", GetLastError()));
  163. Status = STATUS_INTERNAL_ERROR;
  164. return (Status);
  165. }
  166. //
  167. // Convert to ASCII, doubling the length, and add to nonce
  168. //
  169. BinToHex( abRandomData, RANDDATA_BYTESIZE, acRandomHex);
  170. memcpy(pstrNonce->Buffer + NONCE_RANDDATA_LOC, acRandomHex, (2 * RANDDATA_BYTESIZE));
  171. //
  172. // Now calculate the Hash. It will be NULL terminated but STRING length does not include NULL
  173. //
  174. Status = NonceHash((LPBYTE) pstrNonce->Buffer, (2 * sizeof(time_t)),
  175. (LPBYTE) acRandomHex, (2 * RANDDATA_BYTESIZE),
  176. (LPBYTE) g_cNoncePrivateKey, (2 * NONCE_PRIVATE_KEY_BYTESIZE),
  177. (LPBYTE) (pstrNonce->Buffer + NONCE_HASH_LOC));
  178. if (!NT_SUCCESS (Status))
  179. {
  180. DebugLog((DEB_ERROR, "NonceCreate: failed %d\n", Status));
  181. goto CleanUp;
  182. }
  183. pstrNonce->Length = NONCE_SIZE;
  184. CleanUp:
  185. if (!NT_SUCCESS(Status))
  186. {
  187. pstrNonce->Length = 0;
  188. }
  189. DebugLog((DEB_TRACE_FUNC, "NonceCreate: Leaving\n"));
  190. return (Status);
  191. }
  192. //+--------------------------------------------------------------------
  193. //
  194. // Function: NonceIsValid
  195. //
  196. // Synopsis: Called with a pointer to a Nonce and returns NTSTATUS This is the
  197. // main function that checks for a valid nonce.
  198. //
  199. // Arguments: None
  200. //
  201. // Returns: NTSTATUS STATUS_SUCCESS if NONCE generated locally and is valid
  202. //
  203. // Notes:
  204. //
  205. //---------------------------------------------------------------------
  206. NTSTATUS
  207. NonceIsValid(
  208. PSTRING pstrNonce
  209. )
  210. {
  211. NTSTATUS Status = STATUS_SUCCESS;
  212. DebugLog((DEB_TRACE_FUNC, "NonceIsValid: Entering\n"));
  213. // Check the size first
  214. if (pstrNonce->Length != NONCE_SIZE)
  215. {
  216. DebugLog((DEB_ERROR, "NonceIsValid: Incorrect size for the Nonce\n"));
  217. return STATUS_UNSUCCESSFUL;
  218. }
  219. if (!pstrNonce->Buffer)
  220. {
  221. DebugLog((DEB_ERROR, "NonceIsValid: NULL pointer for the Nonce\n"));
  222. return STATUS_UNSUCCESSFUL;
  223. }
  224. if (NonceIsTampered(pstrNonce))
  225. {
  226. DebugLog((DEB_ERROR, "NonceIsValid: Nonce hash does not match\n"));
  227. return STATUS_UNSUCCESSFUL;
  228. }
  229. DebugLog((DEB_TRACE_FUNC, "NonceIsValid: Leaving\n"));
  230. return (Status);
  231. }
  232. /*++
  233. Routine Description:
  234. Creates MD5 hash of input buffer
  235. Arguments:
  236. pbData - data to hash
  237. cbData - size of data pointed to by pbData
  238. pbHash - buffer that receives hash; is assumed to be big enough to contain MD5 hash
  239. Return Value:
  240. TRUE if successful, FALSE if not
  241. --*/
  242. BOOL HashData( BYTE *pbData,
  243. DWORD cbData,
  244. BYTE *pbHash )
  245. {
  246. HCRYPTHASH hHash = NULL;
  247. DebugLog((DEB_TRACE_FUNC, "HashData: Entering\n"));
  248. if ( !CryptCreateHash( g_hCryptProv,
  249. CALG_MD5,
  250. 0,
  251. 0,
  252. &hHash ) )
  253. {
  254. DebugLog((DEB_ERROR, "HashData: CryptCreateHash failed : 0x%lx\n", GetLastError()));
  255. return FALSE;
  256. }
  257. if ( !CryptHashData( hHash,
  258. pbData,
  259. cbData,
  260. 0 ) )
  261. {
  262. DebugLog((DEB_ERROR, "HashData: CryptCreateHash failed : 0x%lx\n", GetLastError()));
  263. CryptDestroyHash( hHash );
  264. return FALSE;
  265. }
  266. DWORD cbHash = MD5_HASH_BYTESIZE;
  267. if ( !CryptGetHashParam( hHash,
  268. HP_HASHVAL,
  269. pbHash,
  270. &cbHash,
  271. 0 ) )
  272. {
  273. DebugLog((DEB_ERROR, "HashData: CryptCreateHash failed : 0x%lx\n", GetLastError()));
  274. CryptDestroyHash( hHash );
  275. return FALSE;
  276. }
  277. CryptDestroyHash( hHash );
  278. DebugLog((DEB_TRACE_FUNC, "HashData: Leaving\n"));
  279. return TRUE;
  280. }
  281. /*++
  282. Routine Description:
  283. Creates MD5 hash of the Nonce values
  284. Arguments:
  285. pbTime - pointer to char buffer encoded Time()
  286. cbTime - number of bytes in encoded Time() buffer to process
  287. pbRandom - pointer to char buffer encoded random sequence
  288. cbRandom - number of bytes in encoded random buffer to process
  289. pbTKey - pointer to char buffer encoded private key
  290. cbKey - number of bytes in encoded private key buffer to process
  291. pbHash - pointer to char buffer encoded Nonce Hash
  292. cbHash - number of bytes in encoded Time() buffer to process
  293. Return Value:
  294. STATUS_SUCCESS - normal completion
  295. --*/
  296. NTSTATUS NTAPI
  297. NonceHash( IN LPBYTE pbTime,
  298. IN DWORD cbTime,
  299. IN LPBYTE pbRandom,
  300. IN DWORD cbRandom,
  301. IN LPBYTE pbKey,
  302. IN DWORD cbKey,
  303. OUT LPBYTE pbHash)
  304. {
  305. NTSTATUS Status = STATUS_SUCCESS;
  306. HCRYPTHASH hHash = NULL;
  307. DWORD cbHash = MD5_HASH_BYTESIZE; // Number of bytes for MD5 hash
  308. unsigned char abHashBin[MD5_HASH_BYTESIZE];
  309. char *pbSeparator = COLONSTR;
  310. DebugLog((DEB_TRACE_FUNC, "NonceHash: Entering\n"));
  311. if ( !CryptCreateHash( g_hCryptProv,
  312. CALG_MD5,
  313. 0,
  314. 0,
  315. &hHash ) )
  316. {
  317. DebugLog((DEB_ERROR, "NonceHash: CryptCreateHash failed : 0x%lx\n", GetLastError()));
  318. Status = STATUS_INTERNAL_ERROR;
  319. goto CleanUp;
  320. }
  321. if ( !CryptHashData( hHash,
  322. pbTime,
  323. cbTime,
  324. 0 ) )
  325. {
  326. DebugLog((DEB_ERROR, "NonceHash: CryptCreateHash failed : 0x%lx\n", GetLastError()));
  327. Status = STATUS_INTERNAL_ERROR;
  328. goto CleanUp;
  329. }
  330. if ( !CryptHashData( hHash,
  331. (const unsigned char *)pbSeparator,
  332. COLONSTR_LEN,
  333. 0 ) )
  334. {
  335. DebugLog((DEB_ERROR, "NonceHash: CryptCreateHash failed : 0x%lx\n", GetLastError()));
  336. Status = STATUS_INTERNAL_ERROR;
  337. goto CleanUp;
  338. }
  339. if ( !CryptHashData( hHash,
  340. pbRandom,
  341. cbRandom,
  342. 0 ) )
  343. {
  344. DebugLog((DEB_ERROR, "NonceHash: CryptCreateHash failed : 0x%lx\n", GetLastError()));
  345. Status = STATUS_INTERNAL_ERROR;
  346. goto CleanUp;
  347. }
  348. if ( !CryptHashData( hHash,
  349. (const unsigned char *)pbSeparator,
  350. COLONSTR_LEN,
  351. 0 ) )
  352. {
  353. DebugLog((DEB_ERROR, "NonceHash: CryptCreateHash failed : 0x%lx\n", GetLastError()));
  354. Status = STATUS_INTERNAL_ERROR;
  355. goto CleanUp;
  356. }
  357. if ( !CryptHashData( hHash,
  358. pbKey,
  359. cbKey,
  360. 0 ) )
  361. {
  362. DebugLog((DEB_ERROR, "NonceHash: CryptCreateHash failed : 0x%lx\n", GetLastError()));
  363. Status = STATUS_INTERNAL_ERROR;
  364. goto CleanUp;
  365. }
  366. if ( !CryptGetHashParam( hHash,
  367. HP_HASHVAL,
  368. abHashBin,
  369. &cbHash,
  370. 0 ) )
  371. {
  372. DebugLog((DEB_ERROR, "NonceHash: CryptCreateHash failed : 0x%lx\n", GetLastError()));
  373. Status = STATUS_INTERNAL_ERROR;
  374. goto CleanUp;
  375. }
  376. // Now convert the Hash to hex
  377. BinToHex(abHashBin, MD5_HASH_BYTESIZE, (char *)pbHash);
  378. CleanUp:
  379. if (hHash)
  380. {
  381. CryptDestroyHash( hHash );
  382. hHash = NULL;
  383. }
  384. DebugLog((DEB_TRACE_FUNC, "NonceHash: Leaving\n"));
  385. return(Status);
  386. }
  387. //+--------------------------------------------------------------------
  388. //
  389. // Function: NonceIsTampered
  390. //
  391. // Synopsis: Check the hash matches for the Nonce
  392. //
  393. // Arguments: None
  394. //
  395. // Returns: TRUE/FALSE if Nonce hash fails check
  396. //
  397. // Notes: Called from NonceIsValid
  398. //
  399. //---------------------------------------------------------------------
  400. BOOL NonceIsTampered(PSTRING pstrNonce)
  401. {
  402. BOOL bStatus = FALSE;
  403. NTSTATUS Status = STATUS_SUCCESS;
  404. unsigned char abHashHex[(2*MD5_HASH_BYTESIZE) + 1];
  405. DebugLog((DEB_TRACE_FUNC, "NonceIsTampered:Entering \n"));
  406. Status = NonceHash((LPBYTE) (pstrNonce->Buffer + NONCE_TIME_LOC), (2 * sizeof(time_t)),
  407. (LPBYTE) (pstrNonce->Buffer + NONCE_RANDDATA_LOC), (2 * RANDDATA_BYTESIZE),
  408. (LPBYTE) g_cNoncePrivateKey, (2 * NONCE_PRIVATE_KEY_BYTESIZE),
  409. (LPBYTE) abHashHex);
  410. if (!NT_SUCCESS (Status))
  411. {
  412. DebugLog((DEB_ERROR, "NonceIsTampered: NonceHash has failed %d\n", Status));
  413. bStatus = TRUE;
  414. goto CleanUp;
  415. }
  416. if (memcmp(abHashHex, (pstrNonce->Buffer + NONCE_HASH_LOC), (2 * MD5_HASH_BYTESIZE)))
  417. {
  418. DebugLog((DEB_ERROR, "NonceIsTampered: memcmp failed\n"));
  419. bStatus = TRUE;
  420. goto CleanUp;
  421. }
  422. CleanUp:
  423. DebugLog((DEB_TRACE_FUNC, "NonceIsTampered: Leaving\n"));
  424. return bStatus;
  425. }
  426. //+--------------------------------------------------------------------
  427. //
  428. // Function: OpaqueCreate
  429. //
  430. // Synopsis: Creates an Opaque string composed of OPAQUE_SIZE of random data
  431. //
  432. // Arguments: pstrOpque - pointer to a STRING to fillin
  433. // with a new opaque
  434. //
  435. // Returns: STATUS_DATA_ERROR - input NONCE not enough space
  436. // STATUS_SUCCESS - operation completed normally
  437. //
  438. // Notes: Function will return error if Nonce STRING is not empty
  439. // OPAQUE FORMAT
  440. // opaque_binary = rand[OPAQUE_SIZE]
  441. // nonce = Hex(opaque_binary)
  442. //
  443. //---------------------------------------------------------------------
  444. NTSTATUS NTAPI
  445. OpaqueCreate(
  446. IN OUT PSTRING pstrOpaque
  447. )
  448. {
  449. NTSTATUS Status = STATUS_SUCCESS;
  450. BYTE abRandomData[OPAQUE_RANDATA_SIZE];
  451. DebugLog((DEB_TRACE_FUNC, "OpaqueCreate: Entering\n"));
  452. // Check to make sure that there is enough space on ouput string
  453. // Need room for the Nonce and the NULL terminator
  454. if (!pstrOpaque->Buffer)
  455. {
  456. Status = StringAllocate(pstrOpaque, OPAQUE_SIZE);
  457. if (!NT_SUCCESS (Status))
  458. {
  459. Status = SEC_E_INSUFFICIENT_MEMORY;
  460. DebugLog((DEB_ERROR, "OpaqueCreate: StringAllocate error 0x%x\n", Status));
  461. goto CleanUp;
  462. }
  463. }
  464. else if (pstrOpaque->MaximumLength < ((2 * OPAQUE_RANDATA_SIZE) + 1))
  465. {
  466. DebugLog((DEB_ERROR, "OpaqueCreate: Input STRING too small\n"));
  467. Status = STATUS_BUFFER_TOO_SMALL;
  468. goto CleanUp;
  469. }
  470. //
  471. // Generate and copy over the random bytes
  472. //
  473. if ( !CryptGenRandom( g_hCryptProv,
  474. OPAQUE_RANDATA_SIZE,
  475. abRandomData ) )
  476. {
  477. DebugLog((DEB_TRACE, "OpaqueCreate: CryptGenRandom() failed : 0x%lx\n", GetLastError()));
  478. Status = STATUS_INTERNAL_ERROR;
  479. return (Status);
  480. }
  481. //
  482. // Convert to ASCII, doubling the length, and add to nonce
  483. //
  484. BinToHex( abRandomData, OPAQUE_RANDATA_SIZE, pstrOpaque->Buffer);
  485. pstrOpaque->Length = (2 * OPAQUE_RANDATA_SIZE);
  486. CleanUp:
  487. if (!NT_SUCCESS(Status))
  488. {
  489. pstrOpaque->Length = 0;
  490. }
  491. DebugLog((DEB_TRACE_FUNC, "OpaqueCreate: Leaving\n"));
  492. return (Status);
  493. }