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.

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