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.

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