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.

562 lines
17 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995.
  5. //
  6. // File: ssl2msg.c
  7. //
  8. // Contents:
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 10-21-97 jbanes Added CAPI integration
  15. //
  16. //----------------------------------------------------------------------------
  17. #include <spbase.h>
  18. #if 0
  19. Ssl2CipherMap Ssl2CipherRank[] =
  20. {
  21. {SSL_CK_RC4_128_WITH_MD5, CALG_MD5, CALG_RC4, 128, SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX},
  22. {SSL_CK_DES_192_EDE3_CBC_WITH_MD5, CALG_MD5, CALG_3DES, 168, SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX},
  23. {SSL_CK_RC2_128_CBC_WITH_MD5, CALG_MD5, CALG_RC2, 128, SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX},
  24. {SSL_CK_RC4_128_FINANCE64_WITH_MD5, CALG_MD5, CALG_RC4, 64, SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX},
  25. {SSL_CK_DES_64_CBC_WITH_MD5, CALG_MD5, CALG_DES, 56, SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX},
  26. {SSL_CK_RC4_128_EXPORT40_WITH_MD5, CALG_MD5, CALG_RC4, 40, SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX},
  27. {SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5, CALG_MD5, CALG_RC2, 40, SP_EXCH_RSA_PKCS1, CALG_RSA_KEYX}
  28. };
  29. DWORD Ssl2NumCipherRanks = sizeof(Ssl2CipherRank)/sizeof(Ssl2CipherMap);
  30. #endif
  31. #if 0
  32. CertTypeMap aSsl2CertEncodingPref[] =
  33. {
  34. { X509_ASN_ENCODING, 0}
  35. };
  36. DWORD cSsl2CertEncodingPref = sizeof(aSsl2CertEncodingPref)/sizeof(CertTypeMap);
  37. #endif
  38. SP_STATUS WINAPI
  39. Ssl2DecryptHandler(
  40. PSPContext pContext,
  41. PSPBuffer pCommInput,
  42. PSPBuffer pAppOutput)
  43. {
  44. SP_STATUS pctRet = PCT_ERR_OK;
  45. if (pCommInput->cbData > 0)
  46. {
  47. // First, we'll handle incoming data packets:
  48. if ((pContext->State & SP_STATE_CONNECTED) && pContext->Decrypt)
  49. {
  50. pctRet = pContext->Decrypt(
  51. pContext,
  52. pCommInput, // message
  53. pAppOutput); // Unpacked Message
  54. if (PCT_ERR_OK == pctRet)
  55. {
  56. /* look for escapes */
  57. }
  58. return(pctRet);
  59. }
  60. else
  61. {
  62. return(SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG));
  63. }
  64. }
  65. return (PCT_INT_INCOMPLETE_MSG);
  66. }
  67. //+---------------------------------------------------------------------------
  68. //
  69. // Function: Ssl2ComputeMac
  70. //
  71. // Synopsis: Compute an SSL2 message MAC.
  72. //
  73. // Arguments: [pContext] -- Schannel context.
  74. //
  75. // History: 10-22-97 jbanes Created.
  76. //
  77. // Notes: MAC_DATA := Hash(key + data + sequence_number)
  78. //
  79. //----------------------------------------------------------------------------
  80. static SP_STATUS
  81. Ssl2ComputeMac(
  82. PSPContext pContext, // in
  83. BOOL fWriteMAC, // in
  84. DWORD dwSequence, // in
  85. PSPBuffer pData, // in
  86. PBYTE pbMac, // out
  87. DWORD cbMac) // in
  88. {
  89. DWORD dwReverseSequence;
  90. BYTE rgbSalt[SP_MAX_MASTER_KEY];
  91. DWORD cbSalt;
  92. HCRYPTHASH hHash;
  93. HCRYPTKEY hKey;
  94. // Make sure output buffer is big enough.
  95. if(cbMac < pContext->pHashInfo->cbCheckSum)
  96. {
  97. return SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL);
  98. }
  99. dwReverseSequence = htonl(dwSequence);
  100. hKey = fWriteMAC ? pContext->hWriteKey : pContext->hReadKey;
  101. if(!CryptCreateHash(pContext->RipeZombie->hMasterProv,
  102. pContext->pHashInfo->aiHash,
  103. 0,
  104. 0,
  105. &hHash))
  106. {
  107. SP_LOG_RESULT(GetLastError());
  108. SP_RETURN(PCT_INT_INTERNAL_ERROR);
  109. }
  110. if(!CryptHashSessionKey(hHash,
  111. hKey,
  112. CRYPT_LITTLE_ENDIAN))
  113. {
  114. SP_LOG_RESULT(GetLastError());
  115. CryptDestroyHash(hHash);
  116. SP_RETURN(PCT_INT_INTERNAL_ERROR);
  117. }
  118. cbSalt = sizeof(rgbSalt);
  119. if(!CryptGetKeyParam(hKey,
  120. KP_SALT,
  121. rgbSalt,
  122. &cbSalt,
  123. 0))
  124. {
  125. SP_LOG_RESULT(GetLastError());
  126. CryptDestroyHash(hHash);
  127. SP_RETURN(PCT_INT_INTERNAL_ERROR);
  128. }
  129. if(!CryptHashData(hHash, rgbSalt, cbSalt, 0))
  130. {
  131. SP_LOG_RESULT(GetLastError());
  132. CryptDestroyHash(hHash);
  133. SP_RETURN(PCT_INT_INTERNAL_ERROR);
  134. }
  135. if(!CryptHashData(hHash,
  136. pData->pvBuffer,
  137. pData->cbData,
  138. 0))
  139. {
  140. SP_LOG_RESULT(GetLastError());
  141. CryptDestroyHash(hHash);
  142. SP_RETURN(PCT_INT_INTERNAL_ERROR);
  143. }
  144. if(!CryptHashData(hHash,
  145. (PBYTE)&dwReverseSequence,
  146. sizeof(DWORD),
  147. 0))
  148. {
  149. SP_LOG_RESULT(GetLastError());
  150. CryptDestroyHash(hHash);
  151. SP_RETURN(PCT_INT_INTERNAL_ERROR);
  152. }
  153. if(!CryptGetHashParam(hHash,
  154. HP_HASHVAL,
  155. pbMac,
  156. &cbMac,
  157. 0))
  158. {
  159. SP_LOG_RESULT(GetLastError());
  160. CryptDestroyHash(hHash);
  161. SP_RETURN(PCT_INT_INTERNAL_ERROR);
  162. }
  163. CryptDestroyHash(hHash);
  164. return PCT_ERR_OK;
  165. }
  166. //+---------------------------------------------------------------------------
  167. //
  168. // Function: Ssl2EncryptMessage
  169. //
  170. // Synopsis: Encode a block of data as an SSL2 record.
  171. //
  172. // Arguments: [pContext] -- Schannel context.
  173. // [pAppInput] -- Data to be encrypted.
  174. // [pCommOutput] -- (output) Completed SSL2 record.
  175. //
  176. // History: 10-22-97 jbanes CAPI integrated.
  177. //
  178. // Notes: An SSL2 record is usually formatted as:
  179. //
  180. // BYTE header[2];
  181. // BYTE mac[mac_size];
  182. // BYTE data[pAppInput->cbData];
  183. //
  184. // If a block cipher is used, and the data to be encrypted
  185. // consists of a partial number of blocks, then the following
  186. // format is used:
  187. //
  188. // BYTE header[3];
  189. // BYTE mac[mac_size];
  190. // BYTE data[pAppInput->cbData];
  191. // BYTE padding[padding_size];
  192. //
  193. //----------------------------------------------------------------------------
  194. SP_STATUS WINAPI
  195. Ssl2EncryptMessage(
  196. PSPContext pContext,
  197. PSPBuffer pAppInput,
  198. PSPBuffer pCommOutput)
  199. {
  200. SP_STATUS pctRet;
  201. DWORD cPadding;
  202. SPBuffer Clean;
  203. SPBuffer Encrypted;
  204. SP_BEGIN("Ssl2EncryptMessage");
  205. /* Estimate if we have padding or not */
  206. Encrypted.cbData = pAppInput->cbData + pContext->pHashInfo->cbCheckSum;
  207. cPadding = (Encrypted.cbData % pContext->pCipherInfo->dwBlockSize);
  208. if(cPadding)
  209. {
  210. cPadding = pContext->pCipherInfo->dwBlockSize - cPadding;
  211. }
  212. Encrypted.cbData += cPadding;
  213. if(cPadding)
  214. {
  215. if(pCommOutput->cbBuffer + Encrypted.cbData + cPadding < 3)
  216. {
  217. SP_RETURN(SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL));
  218. }
  219. Encrypted.pvBuffer = (PUCHAR)pCommOutput->pvBuffer + 3;
  220. Encrypted.cbBuffer = pCommOutput->cbBuffer - 3;
  221. }
  222. else
  223. {
  224. if(pCommOutput->cbBuffer + Encrypted.cbData + cPadding < 2)
  225. {
  226. SP_RETURN(SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL));
  227. }
  228. Encrypted.pvBuffer = (PUCHAR)pCommOutput->pvBuffer + 2;
  229. Encrypted.cbBuffer = pCommOutput->cbBuffer - 2;
  230. }
  231. DebugLog((DEB_TRACE, "Sealing message %x\n", pContext->WriteCounter));
  232. /* Move data out of the way if necessary */
  233. if((PUCHAR)Encrypted.pvBuffer + pContext->pHashInfo->cbCheckSum != pAppInput->pvBuffer)
  234. {
  235. DebugLog((DEB_WARN, "SSL2EncryptMessage: Unnecessary Move, performance hog\n"));
  236. /* if caller wasn't being smart, then we must copy memory here */
  237. MoveMemory((PUCHAR)Encrypted.pvBuffer + pContext->pHashInfo->cbCheckSum,
  238. pAppInput->pvBuffer,
  239. pAppInput->cbData);
  240. }
  241. // Initialize pad
  242. if(cPadding)
  243. {
  244. FillMemory((PUCHAR)Encrypted.pvBuffer + pContext->pHashInfo->cbCheckSum + pAppInput->cbData, cPadding, 0);
  245. }
  246. // Compute MAC.
  247. Clean.pvBuffer = (PBYTE)Encrypted.pvBuffer + pContext->pHashInfo->cbCheckSum;
  248. Clean.cbData = Encrypted.cbData - pContext->pHashInfo->cbCheckSum;
  249. Clean.cbBuffer = Clean.cbData;
  250. pctRet = Ssl2ComputeMac(pContext,
  251. TRUE,
  252. pContext->WriteCounter,
  253. &Clean,
  254. Encrypted.pvBuffer,
  255. pContext->pHashInfo->cbCheckSum);
  256. if(pctRet != PCT_ERR_OK)
  257. {
  258. SP_RETURN(pctRet);
  259. }
  260. // Encrypt buffer.
  261. if(!CryptEncrypt(pContext->hWriteKey,
  262. 0, FALSE, 0,
  263. Encrypted.pvBuffer,
  264. &Encrypted.cbData,
  265. Encrypted.cbBuffer))
  266. {
  267. SP_LOG_RESULT(GetLastError());
  268. SP_RETURN(PCT_INT_INTERNAL_ERROR);
  269. }
  270. /* set sizes */
  271. if(cPadding)
  272. {
  273. if(Encrypted.cbData > 0x3fff)
  274. {
  275. SP_RETURN(SP_LOG_RESULT(PCT_INT_DATA_OVERFLOW));
  276. }
  277. ((PUCHAR)pCommOutput->pvBuffer)[0]= (UCHAR)(0x3f & (Encrypted.cbData>>8));
  278. ((PUCHAR)pCommOutput->pvBuffer)[1]= (UCHAR)(0xff & Encrypted.cbData);
  279. ((PUCHAR)pCommOutput->pvBuffer)[2]= (UCHAR)cPadding;
  280. }
  281. else
  282. {
  283. if(Encrypted.cbData > 0x7fff)
  284. {
  285. SP_RETURN(SP_LOG_RESULT(PCT_INT_DATA_OVERFLOW));
  286. }
  287. ((PUCHAR)pCommOutput->pvBuffer)[0]= (UCHAR)(0x7f & (Encrypted.cbData>>8)) | 0x80;
  288. ((PUCHAR)pCommOutput->pvBuffer)[1]= (UCHAR)(0xff & Encrypted.cbData);
  289. }
  290. pCommOutput->cbData = Encrypted.cbData + (cPadding?3:2);
  291. pContext->WriteCounter ++ ;
  292. SP_RETURN( PCT_ERR_OK );
  293. }
  294. SP_STATUS WINAPI
  295. Ssl2GetHeaderSize(
  296. PSPContext pContext,
  297. PSPBuffer pCommInput,
  298. DWORD * pcbHeaderSize)
  299. {
  300. if(pcbHeaderSize == NULL)
  301. {
  302. return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
  303. }
  304. if(pCommInput->cbData < 1)
  305. {
  306. return (PCT_INT_INCOMPLETE_MSG);
  307. }
  308. if( ((PUCHAR)pCommInput->pvBuffer)[0]&0x80 )
  309. {
  310. *pcbHeaderSize = 2 + pContext->pHashInfo->cbCheckSum;
  311. }
  312. else
  313. {
  314. *pcbHeaderSize = 3 + pContext->pHashInfo->cbCheckSum;
  315. }
  316. return PCT_ERR_OK;
  317. }
  318. //+---------------------------------------------------------------------------
  319. //
  320. // Function: Ssl2DecryptMessage
  321. //
  322. // Synopsis: Decode an SSL2 record.
  323. //
  324. // Arguments: [pContext] -- Schannel context.
  325. // [pMessage] -- Data from the remote party.
  326. // [pAppOutput] -- (output) Decrypted data.
  327. //
  328. // History: 10-22-97 jbanes CAPI integrated.
  329. //
  330. // Notes: An SSL2 record is usually formatted as:
  331. //
  332. // BYTE header[2];
  333. // BYTE mac[mac_size];
  334. // BYTE data[pAppInput->cbData];
  335. //
  336. // If a block cipher is used, and the data to be encrypted
  337. // consists of a partial number of blocks, then the following
  338. // format is used:
  339. //
  340. // BYTE header[3];
  341. // BYTE mac[mac_size];
  342. // BYTE data[pAppInput->cbData];
  343. // BYTE padding[padding_size];
  344. //
  345. // The number of input data bytes consumed by this function
  346. // is returned in pMessage->cbData.
  347. //
  348. //----------------------------------------------------------------------------
  349. SP_STATUS WINAPI
  350. Ssl2DecryptMessage(
  351. PSPContext pContext,
  352. PSPBuffer pMessage,
  353. PSPBuffer pAppOutput)
  354. {
  355. SP_STATUS pctRet;
  356. DWORD cPadding;
  357. DWORD dwLength;
  358. SPBuffer Encrypted;
  359. SPBuffer Clean;
  360. DWORD cbActualData;
  361. UCHAR Digest[SP_MAX_DIGEST_LEN];
  362. SP_BEGIN("Ssl2DecryptMessage");
  363. /* First determine the length of data, the length of padding,
  364. * and the location of data, and the location of MAC */
  365. cbActualData = pMessage->cbData;
  366. pMessage->cbData = 2; /* minimum amount of data we need */
  367. if(pMessage->cbData > cbActualData)
  368. {
  369. SP_RETURN(PCT_INT_INCOMPLETE_MSG);
  370. }
  371. DebugLog((DEB_TRACE, " Incomming Buffer: %lx, size %ld (%lx)\n", pMessage->pvBuffer, cbActualData, cbActualData));
  372. if(((PUCHAR)pMessage->pvBuffer)[0] & 0x80)
  373. {
  374. /* 2 byte header */
  375. cPadding = 0;
  376. dwLength = ((((PUCHAR)pMessage->pvBuffer)[0] & 0x7f) << 8) |
  377. ((PUCHAR)pMessage->pvBuffer)[1];
  378. Encrypted.pvBuffer = (PUCHAR)pMessage->pvBuffer + 2;
  379. Encrypted.cbBuffer = pMessage->cbBuffer - 2;
  380. }
  381. else
  382. {
  383. pMessage->cbData++;
  384. if(pMessage->cbData > cbActualData)
  385. {
  386. SP_RETURN(PCT_INT_INCOMPLETE_MSG);
  387. }
  388. /* 3 byte header */
  389. cPadding = ((PUCHAR)pMessage->pvBuffer)[2];
  390. dwLength = ((((PUCHAR)pMessage->pvBuffer)[0] & 0x3f) << 8) |
  391. ((PUCHAR)pMessage->pvBuffer)[1];
  392. Encrypted.pvBuffer = (PUCHAR)pMessage->pvBuffer + 3;
  393. Encrypted.cbBuffer = pMessage->cbBuffer - 3;
  394. }
  395. /* Now we know how mutch data we will eat, so set cbData on the Input to be that size */
  396. pMessage->cbData += dwLength;
  397. /* do we have enough bytes for the reported data */
  398. if(pMessage->cbData > cbActualData)
  399. {
  400. SP_RETURN(PCT_INT_INCOMPLETE_MSG);
  401. }
  402. /* do we have enough data for our checksum */
  403. if(dwLength < pContext->pHashInfo->cbCheckSum + cPadding)
  404. {
  405. SP_RETURN(SP_LOG_RESULT(PCT_INT_MSG_ALTERED));
  406. }
  407. Encrypted.cbData = dwLength; /* encrypted data size */
  408. Encrypted.cbBuffer = Encrypted.cbData;
  409. /* check to see if we have a block size violation */
  410. if(Encrypted.cbData % pContext->pCipherInfo->dwBlockSize)
  411. {
  412. SP_RETURN(SP_LOG_RESULT(PCT_INT_MSG_ALTERED));
  413. }
  414. /* Decrypt */
  415. if(!CryptDecrypt(pContext->hReadKey,
  416. 0, FALSE, 0,
  417. Encrypted.pvBuffer,
  418. &Encrypted.cbData))
  419. {
  420. SP_LOG_RESULT(GetLastError());
  421. SP_RETURN(PCT_INT_INTERNAL_ERROR);
  422. }
  423. // Compute MAC.
  424. Clean.pvBuffer = (PBYTE)Encrypted.pvBuffer + pContext->pHashInfo->cbCheckSum;
  425. Clean.cbData = Encrypted.cbData - pContext->pHashInfo->cbCheckSum;
  426. Clean.cbBuffer = Clean.cbData;
  427. pctRet = Ssl2ComputeMac(pContext,
  428. FALSE,
  429. pContext->ReadCounter,
  430. &Clean,
  431. Digest,
  432. sizeof(Digest));
  433. if(pctRet != PCT_ERR_OK)
  434. {
  435. SP_RETURN(pctRet);
  436. }
  437. // the padding is computed in the hash but is not needed after this
  438. Clean.cbData -= cPadding;
  439. DebugLog((DEB_TRACE, "Unsealing message %x\n", pContext->ReadCounter));
  440. pContext->ReadCounter++;
  441. if(memcmp(Digest, Encrypted.pvBuffer, pContext->pHashInfo->cbCheckSum ) )
  442. {
  443. SP_RETURN(SP_LOG_RESULT(PCT_INT_MSG_ALTERED));
  444. }
  445. if(pAppOutput->pvBuffer != Clean.pvBuffer)
  446. {
  447. DebugLog((DEB_WARN, "SSL2DecryptMessage: Unnecessary Move, performance hog\n"));
  448. MoveMemory(pAppOutput->pvBuffer,
  449. Clean.pvBuffer,
  450. Clean.cbData);
  451. }
  452. pAppOutput->cbData = Clean.cbData;
  453. DebugLog((DEB_TRACE, " TotalData: size %ld (%lx)\n", pMessage->cbData, pMessage->cbData));
  454. SP_RETURN( PCT_ERR_OK );
  455. }
  456. #if 0
  457. SP_STATUS
  458. Ssl2MakeMasterKeyBlock(PSPContext pContext)
  459. {
  460. MD5_CTX Md5Hash;
  461. UCHAR cSalt;
  462. UCHAR ib;
  463. //pContext->RipeZombe->pMasterKey containst the master secret.
  464. #if DBG
  465. DebugLog((DEB_TRACE, " Master Secret\n"));
  466. DBG_HEX_STRING(DEB_TRACE,pContext->RipeZombie->pMasterKey, pContext->RipeZombie->cbMasterKey);
  467. #endif
  468. for(ib=0 ; ib<3 ; ib++)
  469. {
  470. // MD5(master_secret + SHA-hash)
  471. MD5Init (&Md5Hash);
  472. MD5Update(&Md5Hash, pContext->RipeZombie->pMasterKey, pContext->RipeZombie->cbMasterKey);
  473. // We're going to be bug-for-bug compatable with netscape, so
  474. // we always add the digit into the hash, instead of following
  475. // the spec which says don't add the digit for DES
  476. //if(pContext->RipeZombie->aiCipher != CALG_DES)
  477. {
  478. cSalt = ib+'0';
  479. MD5Update(&Md5Hash, &cSalt, 1);
  480. }
  481. MD5Update(&Md5Hash, pContext->pChallenge, pContext->cbChallenge);
  482. MD5Update(&Md5Hash, pContext->pConnectionID, pContext->cbConnectionID);
  483. MD5Final (&Md5Hash);
  484. CopyMemory(pContext->Ssl3MasterKeyBlock + ib * MD5DIGESTLEN, Md5Hash.digest, MD5DIGESTLEN);
  485. }
  486. #if DBG
  487. DebugLog((DEB_TRACE, " Master Key Block\n"));
  488. DBG_HEX_STRING(DEB_TRACE,pContext->Ssl3MasterKeyBlock, MD5DIGESTLEN*3);
  489. #endif
  490. return( PCT_ERR_OK );
  491. }
  492. #endif