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.

537 lines
14 KiB

  1. /*-----------------------------------------------------------------------------
  2. * Copyright (C) Microsoft Corporation, 1995 - 1996.
  3. * All rights reserved.
  4. *
  5. * Owner : ramas
  6. * Date : 5/03/97
  7. * description : Main Crypto functions for TLS1
  8. *----------------------------------------------------------------------------*/
  9. #include <spbase.h>
  10. #define DEB_TLS1KEYS 0x01000000
  11. //+---------------------------------------------------------------------------
  12. //
  13. // Function: Tls1MakeWriteSessionKeys
  14. //
  15. // Synopsis:
  16. //
  17. // Arguments: [pContext] -- Schannel context.
  18. //
  19. // History: 10-10-97 jbanes Added server-side CAPI integration.
  20. //
  21. // Notes:
  22. //
  23. //----------------------------------------------------------------------------
  24. SP_STATUS
  25. Tls1MakeWriteSessionKeys(PSPContext pContext)
  26. {
  27. BOOL fClient;
  28. // Determine if we're a client or a server.
  29. fClient = (0 != (pContext->RipeZombie->fProtocol & SP_PROT_TLS1_CLIENT));
  30. if(pContext->hWriteKey)
  31. {
  32. if(!CryptDestroyKey(pContext->hWriteKey))
  33. {
  34. SP_LOG_RESULT(GetLastError());
  35. }
  36. }
  37. pContext->hWriteProv = pContext->RipeZombie->hMasterProv;
  38. pContext->hWriteKey = pContext->hPendingWriteKey;
  39. pContext->hPendingWriteKey = 0;
  40. if(pContext->hWriteMAC)
  41. {
  42. if(!CryptDestroyKey(pContext->hWriteMAC))
  43. {
  44. SP_LOG_RESULT(GetLastError());
  45. }
  46. }
  47. pContext->hWriteMAC = pContext->hPendingWriteMAC;
  48. pContext->hPendingWriteMAC = 0;
  49. return PCT_ERR_OK;
  50. }
  51. //+---------------------------------------------------------------------------
  52. //
  53. // Function: Tls1MakeReadSessionKeys
  54. //
  55. // Synopsis:
  56. //
  57. // Arguments: [pContext] -- Schannel context.
  58. //
  59. // History: 10-10-97 jbanes Added server-side CAPI integration.
  60. //
  61. // Notes:
  62. //
  63. //----------------------------------------------------------------------------
  64. SP_STATUS
  65. Tls1MakeReadSessionKeys(PSPContext pContext)
  66. {
  67. BOOL fClient;
  68. // Determine if we're a client or a server.
  69. fClient = (0 != (pContext->RipeZombie->fProtocol & SP_PROT_TLS1_CLIENT));
  70. if(pContext->hReadKey)
  71. {
  72. if(!CryptDestroyKey(pContext->hReadKey))
  73. {
  74. SP_LOG_RESULT(GetLastError());
  75. }
  76. }
  77. pContext->hReadProv = pContext->RipeZombie->hMasterProv;
  78. pContext->hReadKey = pContext->hPendingReadKey;
  79. pContext->hPendingReadKey = 0;
  80. if(pContext->hReadMAC)
  81. {
  82. if(!CryptDestroyKey(pContext->hReadMAC))
  83. {
  84. SP_LOG_RESULT(GetLastError());
  85. }
  86. }
  87. pContext->hReadMAC = pContext->hPendingReadMAC;
  88. pContext->hPendingReadMAC = 0;
  89. return PCT_ERR_OK;
  90. }
  91. //+---------------------------------------------------------------------------
  92. //
  93. // Function: Tls1ComputeMac
  94. //
  95. // Synopsis:
  96. //
  97. // Arguments: [pContext] --
  98. // [hSecret] --
  99. // [dwSequence] --
  100. // [pClean] --
  101. // [cContentType] --
  102. // [pbMac] --
  103. // [cbMac]
  104. //
  105. // History: 10-03-97 jbanes Created.
  106. //
  107. // Notes:
  108. //
  109. //----------------------------------------------------------------------------
  110. SP_STATUS
  111. Tls1ComputeMac(
  112. PSPContext pContext,
  113. BOOL fReadMac,
  114. PSPBuffer pClean,
  115. CHAR cContentType,
  116. PBYTE pbMac,
  117. DWORD cbMac)
  118. {
  119. HCRYPTHASH hHash;
  120. HMAC_INFO HmacInfo;
  121. PBYTE pbData;
  122. DWORD cbData;
  123. DWORD cbDataReverse;
  124. DWORD dwReverseSequence;
  125. UCHAR rgbData1[15];
  126. PUCHAR pbData1;
  127. DWORD cbData1;
  128. HCRYPTPROV hProv;
  129. HCRYPTKEY hSecret;
  130. DWORD dwSequence;
  131. PHashInfo pHashInfo;
  132. pbData = pClean->pvBuffer;
  133. cbData = pClean->cbData;
  134. if(cbData & 0xFFFF0000)
  135. {
  136. return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  137. }
  138. if(fReadMac)
  139. {
  140. hProv = pContext->hReadProv;
  141. hSecret = pContext->hReadMAC;
  142. dwSequence = pContext->ReadCounter;
  143. pHashInfo = pContext->pReadHashInfo;
  144. }
  145. else
  146. {
  147. hProv = pContext->hWriteProv;
  148. hSecret = pContext->hWriteMAC;
  149. dwSequence = pContext->WriteCounter;
  150. pHashInfo = pContext->pWriteHashInfo;
  151. }
  152. if(!hProv)
  153. {
  154. return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  155. }
  156. // Create hash object.
  157. if(!CryptCreateHash(hProv,
  158. CALG_HMAC,
  159. hSecret,
  160. 0,
  161. &hHash))
  162. {
  163. SP_LOG_RESULT(GetLastError());
  164. return PCT_INT_INTERNAL_ERROR;
  165. }
  166. // Specify hash algorithm.
  167. ZeroMemory(&HmacInfo, sizeof(HMAC_INFO));
  168. HmacInfo.HashAlgid = pHashInfo->aiHash;
  169. if(!CryptSetHashParam(hHash,
  170. HP_HMAC_INFO,
  171. (PBYTE)&HmacInfo,
  172. 0))
  173. {
  174. SP_LOG_RESULT(GetLastError());
  175. CryptDestroyHash(hHash);
  176. return PCT_INT_INTERNAL_ERROR;
  177. }
  178. // Build data to be hashed.
  179. cbData1 = 2 * sizeof(DWORD) + // sequence number (64-bit)
  180. 1 + // content type
  181. 2 + // protocol version
  182. 2; // message length
  183. SP_ASSERT(cbData1 <= sizeof(rgbData1));
  184. pbData1 = rgbData1;
  185. ZeroMemory(pbData1, sizeof(DWORD));
  186. pbData1 += sizeof(DWORD);
  187. dwReverseSequence = htonl(dwSequence);
  188. CopyMemory(pbData1, &dwReverseSequence, sizeof(DWORD));
  189. pbData1 += sizeof(DWORD);
  190. *pbData1++ = cContentType;
  191. *pbData1++ = SSL3_CLIENT_VERSION_MSB;
  192. *pbData1++ = TLS1_CLIENT_VERSION_LSB;
  193. cbDataReverse = (cbData >> 8) | (cbData << 8);
  194. CopyMemory(pbData1, &cbDataReverse, 2);
  195. // Hash data.
  196. if(!CryptHashData(hHash, rgbData1, cbData1, 0))
  197. {
  198. SP_LOG_RESULT(GetLastError());
  199. CryptDestroyHash(hHash);
  200. return PCT_INT_INTERNAL_ERROR;
  201. }
  202. if(!CryptHashData(hHash, pbData, cbData, 0))
  203. {
  204. SP_LOG_RESULT(GetLastError());
  205. CryptDestroyHash(hHash);
  206. return PCT_INT_INTERNAL_ERROR;
  207. }
  208. // Get hash value.
  209. if(!CryptGetHashParam(hHash,
  210. HP_HASHVAL,
  211. pbMac,
  212. &cbMac,
  213. 0))
  214. {
  215. SP_LOG_RESULT(GetLastError());
  216. CryptDestroyHash(hHash);
  217. return PCT_INT_INTERNAL_ERROR;
  218. }
  219. SP_ASSERT(cbMac == pHashInfo->cbCheckSum);
  220. #if DBG
  221. DebugLog((DEB_TLS1KEYS, " TLS1 MAC Output"));
  222. DBG_HEX_STRING(DEB_TLS1KEYS, pbMac, cbMac);
  223. #endif
  224. CryptDestroyHash(hHash);
  225. return PCT_ERR_OK;
  226. }
  227. #define HMAC_K_PADSIZE 64
  228. BOOL MyPrimitiveSHA(
  229. PBYTE pbData,
  230. DWORD cbData,
  231. BYTE rgbHash[A_SHA_DIGEST_LEN])
  232. {
  233. BOOL fRet = FALSE;
  234. A_SHA_CTX sSHAHash;
  235. A_SHAInit(&sSHAHash);
  236. A_SHAUpdate(&sSHAHash, (BYTE *) pbData, cbData);
  237. A_SHAFinal(&sSHAHash, rgbHash);
  238. fRet = TRUE;
  239. //Ret:
  240. return fRet;
  241. }
  242. BOOL MyPrimitiveMD5(
  243. PBYTE pbData,
  244. DWORD cbData,
  245. BYTE rgbHash[MD5DIGESTLEN])
  246. {
  247. BOOL fRet = FALSE;
  248. MD5_CTX sMD5Hash;
  249. MD5Init(&sMD5Hash);
  250. MD5Update(&sMD5Hash, (BYTE *) pbData, cbData);
  251. MD5Final(&sMD5Hash);
  252. memcpy(rgbHash, sMD5Hash.digest, MD5DIGESTLEN);
  253. fRet = TRUE;
  254. //Ret:
  255. return fRet;
  256. }
  257. BOOL MyPrimitiveHMACParam(
  258. PBYTE pbKeyMaterial,
  259. DWORD cbKeyMaterial,
  260. PBYTE pbData,
  261. DWORD cbData,
  262. ALG_ID Algid,
  263. BYTE rgbHMAC[A_SHA_DIGEST_LEN])
  264. {
  265. BYTE rgbHMACTmp[HMAC_K_PADSIZE+A_SHA_DIGEST_LEN];
  266. BOOL fRet = FALSE;
  267. BYTE rgbKipad[HMAC_K_PADSIZE];
  268. BYTE rgbKopad[HMAC_K_PADSIZE];
  269. DWORD dwBlock;
  270. // truncate
  271. if (cbKeyMaterial > HMAC_K_PADSIZE)
  272. cbKeyMaterial = HMAC_K_PADSIZE;
  273. ZeroMemory(rgbKipad, HMAC_K_PADSIZE);
  274. CopyMemory(rgbKipad, pbKeyMaterial, cbKeyMaterial);
  275. ZeroMemory(rgbKopad, HMAC_K_PADSIZE);
  276. CopyMemory(rgbKopad, pbKeyMaterial, cbKeyMaterial);
  277. // Kipad, Kopad are padded sMacKey. Now XOR across...
  278. for(dwBlock=0; dwBlock<HMAC_K_PADSIZE/sizeof(DWORD); dwBlock++)
  279. {
  280. ((DWORD*)rgbKipad)[dwBlock] ^= 0x36363636;
  281. ((DWORD*)rgbKopad)[dwBlock] ^= 0x5C5C5C5C;
  282. }
  283. // prepend Kipad to data, Hash to get H1
  284. if (CALG_SHA1 == Algid)
  285. {
  286. // do this inline since it would require data copy
  287. A_SHA_CTX sSHAHash;
  288. BYTE HashVal[A_SHA_DIGEST_LEN];
  289. A_SHAInit(&sSHAHash);
  290. A_SHAUpdate(&sSHAHash, rgbKipad, HMAC_K_PADSIZE);
  291. A_SHAUpdate(&sSHAHash, pbData, cbData);
  292. // Finish off the hash
  293. A_SHAFinal(&sSHAHash, HashVal);
  294. // prepend Kopad to H1, hash to get HMAC
  295. CopyMemory(rgbHMACTmp, rgbKopad, HMAC_K_PADSIZE);
  296. CopyMemory(rgbHMACTmp+HMAC_K_PADSIZE, HashVal, A_SHA_DIGEST_LEN);
  297. if (!MyPrimitiveSHA(
  298. rgbHMACTmp,
  299. HMAC_K_PADSIZE + A_SHA_DIGEST_LEN,
  300. rgbHMAC))
  301. goto Ret;
  302. }
  303. else
  304. {
  305. // do this inline since it would require data copy
  306. MD5_CTX sMD5Hash;
  307. MD5Init(&sMD5Hash);
  308. MD5Update(&sMD5Hash, rgbKipad, HMAC_K_PADSIZE);
  309. MD5Update(&sMD5Hash, pbData, cbData);
  310. MD5Final(&sMD5Hash);
  311. // prepend Kopad to H1, hash to get HMAC
  312. CopyMemory(rgbHMACTmp, rgbKopad, HMAC_K_PADSIZE);
  313. CopyMemory(rgbHMACTmp+HMAC_K_PADSIZE, sMD5Hash.digest, MD5DIGESTLEN);
  314. if (!MyPrimitiveMD5(
  315. rgbHMACTmp,
  316. HMAC_K_PADSIZE + MD5DIGESTLEN,
  317. rgbHMAC))
  318. goto Ret;
  319. }
  320. fRet = TRUE;
  321. Ret:
  322. return fRet;
  323. }
  324. //+ ---------------------------------------------------------------------
  325. // the P_Hash algorithm from TLS
  326. BOOL P_Hash
  327. (
  328. PBYTE pbSecret,
  329. DWORD cbSecret,
  330. PBYTE pbSeed,
  331. DWORD cbSeed,
  332. ALG_ID Algid,
  333. PBYTE pbKeyOut, //Buffer to copy the result...
  334. DWORD cbKeyOut //# of bytes of key length they want as output.
  335. )
  336. {
  337. BOOL fRet = FALSE;
  338. BYTE rgbDigest[A_SHA_DIGEST_LEN];
  339. DWORD iKey;
  340. DWORD cbHash;
  341. PBYTE pbAofiDigest = NULL;
  342. SafeAllocaAllocate(pbAofiDigest, cbSeed + A_SHA_DIGEST_LEN);
  343. if (NULL == pbAofiDigest)
  344. goto Ret;
  345. if (CALG_SHA1 == Algid)
  346. {
  347. cbHash = A_SHA_DIGEST_LEN;
  348. }
  349. else
  350. {
  351. cbHash = MD5DIGESTLEN;
  352. }
  353. // First, we define a data expansion function, P_hash(secret, data)
  354. // which uses a single hash function to expand a secret and seed into
  355. // an arbitrary quantity of output:
  356. // P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
  357. // HMAC_hash(secret, A(2) + seed) +
  358. // HMAC_hash(secret, A(3) + seed) + ...
  359. // Where + indicates concatenation.
  360. // A() is defined as:
  361. // A(0) = seed
  362. // A(i) = HMAC_hash(secret, A(i-1))
  363. // build A(1)
  364. if (!MyPrimitiveHMACParam(pbSecret, cbSecret, pbSeed, cbSeed,
  365. Algid, pbAofiDigest))
  366. goto Ret;
  367. // create Aofi: ( A(i) | seed )
  368. CopyMemory(&pbAofiDigest[cbHash], pbSeed, cbSeed);
  369. for (iKey=0; cbKeyOut; iKey++)
  370. {
  371. // build Digest = HMAC(key | A(i) | seed);
  372. if (!MyPrimitiveHMACParam(pbSecret, cbSecret, pbAofiDigest,
  373. cbSeed + cbHash, Algid, rgbDigest))
  374. goto Ret;
  375. // append to pbKeyOut
  376. if(cbKeyOut < cbHash)
  377. {
  378. CopyMemory(pbKeyOut, rgbDigest, cbKeyOut);
  379. break;
  380. }
  381. else
  382. {
  383. CopyMemory(pbKeyOut, rgbDigest, cbHash);
  384. pbKeyOut += cbHash;
  385. }
  386. cbKeyOut -= cbHash;
  387. // build A(i) = HMAC(key, A(i-1))
  388. if (!MyPrimitiveHMACParam(pbSecret, cbSecret, pbAofiDigest, cbHash,
  389. Algid, pbAofiDigest))
  390. goto Ret;
  391. }
  392. fRet = TRUE;
  393. Ret:
  394. if (pbAofiDigest)
  395. SafeAllocaFree(pbAofiDigest);
  396. return fRet;
  397. }
  398. BOOL PRF(
  399. PBYTE pbSecret,
  400. DWORD cbSecret,
  401. PBYTE pbLabel,
  402. DWORD cbLabel,
  403. PBYTE pbSeed,
  404. DWORD cbSeed,
  405. PBYTE pbKeyOut, //Buffer to copy the result...
  406. DWORD cbKeyOut //# of bytes of key length they want as output.
  407. )
  408. {
  409. BYTE *pbBuff = NULL;
  410. BYTE *pbLabelAndSeed = NULL;
  411. DWORD cbLabelAndSeed;
  412. DWORD cbOdd;
  413. DWORD cbHalfSecret;
  414. DWORD i;
  415. BOOL fRet = FALSE;
  416. cbOdd = cbSecret % 2;
  417. cbHalfSecret = cbSecret / 2;
  418. cbLabelAndSeed = cbLabel + cbSeed;
  419. SafeAllocaAllocate(pbLabelAndSeed, cbLabelAndSeed);
  420. if (NULL == pbLabelAndSeed)
  421. goto Ret;
  422. SafeAllocaAllocate(pbBuff, cbKeyOut);
  423. if (NULL == pbBuff)
  424. goto Ret;
  425. // copy label and seed into one buffer
  426. memcpy(pbLabelAndSeed, pbLabel, cbLabel);
  427. memcpy(pbLabelAndSeed + cbLabel, pbSeed, cbSeed);
  428. // Use P_hash to calculate MD5 half
  429. if (!P_Hash(pbSecret, cbHalfSecret + cbOdd, pbLabelAndSeed,
  430. cbLabelAndSeed, CALG_MD5, pbKeyOut, cbKeyOut))
  431. goto Ret;
  432. // Use P_hash to calculate SHA half
  433. if (!P_Hash(pbSecret + cbHalfSecret, cbHalfSecret + cbOdd, pbLabelAndSeed,
  434. cbLabelAndSeed, CALG_SHA1, pbBuff, cbKeyOut))
  435. goto Ret;
  436. // XOR the two halves
  437. for (i=0;i<cbKeyOut;i++)
  438. {
  439. pbKeyOut[i] = pbKeyOut[i] ^ pbBuff[i];
  440. }
  441. fRet = TRUE;
  442. Ret:
  443. if (pbBuff)
  444. SafeAllocaFree(pbBuff);
  445. if (pbLabelAndSeed)
  446. SafeAllocaFree(pbLabelAndSeed);
  447. return fRet;
  448. }