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.

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