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.

831 lines
25 KiB

  1. /*++
  2. Copyright (c) 1997-2001 Microsoft Corporation
  3. Module Name:
  4. esp.c
  5. Abstract:
  6. This module contains the code to create/verify the ESP headers.
  7. Author:
  8. Sanjay Anand (SanjayAn) 2-January-1997
  9. ChunYe
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. --*/
  14. #include "precomp.h"
  15. #ifdef RUN_WPP
  16. #include "esp.tmh"
  17. #endif
  18. #ifndef _TEST_PERF
  19. CONFID_ALGO conf_algorithms[] = {
  20. { esp_nullinit, esp_nullencrypt, esp_nulldecrypt, DES_BLOCKLEN},
  21. { esp_desinit, esp_desencrypt, esp_desdecrypt, DES_BLOCKLEN},
  22. { esp_desinit, esp_desencrypt, esp_desdecrypt, DES_BLOCKLEN},
  23. { esp_3_desinit, esp_3_desencrypt, esp_3_desdecrypt, DES_BLOCKLEN},
  24. };
  25. #else
  26. CONFID_ALGO conf_algorithms[] = {
  27. { esp_nullinit, esp_nullencrypt, esp_nulldecrypt, DES_BLOCKLEN},
  28. { esp_nullinit, esp_nullencrypt, esp_nulldecrypt, DES_BLOCKLEN},
  29. { esp_nullinit, esp_nullencrypt, esp_nulldecrypt, DES_BLOCKLEN},
  30. { esp_nullinit, esp_nullencrypt, esp_nulldecrypt, DES_BLOCKLEN},
  31. };
  32. #endif
  33. VOID
  34. esp_nullinit (
  35. IN PVOID pState,
  36. IN PUCHAR pKey
  37. )
  38. {
  39. return;
  40. }
  41. NTSTATUS
  42. esp_nullencrypt (
  43. PVOID pState,
  44. PUCHAR pOut,
  45. PUCHAR pIn,
  46. PUCHAR pIV
  47. )
  48. {
  49. RtlCopyMemory(pOut, pIn, DES_BLOCKLEN);
  50. return STATUS_SUCCESS;
  51. }
  52. NTSTATUS
  53. esp_nulldecrypt (
  54. PVOID pState,
  55. PUCHAR pOut,
  56. PUCHAR pIn,
  57. PUCHAR pIV
  58. )
  59. {
  60. return STATUS_SUCCESS;
  61. }
  62. VOID
  63. esp_desinit (
  64. IN PVOID pState,
  65. IN PUCHAR pKey
  66. )
  67. {
  68. DESTable *Table = &((PCONF_STATE_BUFFER)pState)->desTable;
  69. IPSEC_DES_KEY(Table, pKey);
  70. }
  71. NTSTATUS
  72. esp_desencrypt (
  73. PVOID pState,
  74. PUCHAR pOut,
  75. PUCHAR pIn,
  76. PUCHAR pIV
  77. )
  78. {
  79. DESTable *Table = &((PCONF_STATE_BUFFER)pState)->desTable;
  80. if (IPSEC_CBC(IPSEC_DES_ALGO,
  81. pOut,
  82. pIn, // pChunk,
  83. Table,
  84. ENCRYPT,
  85. pIV)) {
  86. return STATUS_SUCCESS;
  87. } else {
  88. return STATUS_UNSUCCESSFUL;
  89. }
  90. }
  91. NTSTATUS
  92. esp_desdecrypt (
  93. PVOID pState,
  94. PUCHAR pOut,
  95. PUCHAR pIn,
  96. PUCHAR pIV
  97. )
  98. {
  99. DESTable *Table = &((PCONF_STATE_BUFFER)pState)->desTable;
  100. if (IPSEC_CBC(IPSEC_DES_ALGO,
  101. pOut,
  102. pIn, // pChunk,
  103. Table,
  104. DECRYPT,
  105. pIV)) {
  106. return STATUS_SUCCESS;
  107. } else {
  108. return STATUS_UNSUCCESSFUL;
  109. }
  110. }
  111. VOID
  112. esp_3_desinit (
  113. IN PVOID pState,
  114. IN PUCHAR pKey
  115. )
  116. {
  117. DES3TABLE *Table = &((PCONF_STATE_BUFFER)pState)->des3Table;
  118. IPSEC_3DES_KEY(Table, pKey);
  119. }
  120. NTSTATUS
  121. esp_3_desencrypt (
  122. PVOID pState,
  123. PUCHAR pOut,
  124. PUCHAR pIn,
  125. PUCHAR pIV
  126. )
  127. {
  128. DES3TABLE *Table = &((PCONF_STATE_BUFFER)pState)->des3Table;
  129. if (IPSEC_CBC(IPSEC_3DES_ALGO,
  130. pOut,
  131. pIn, // pChunk,
  132. Table,
  133. ENCRYPT,
  134. pIV)) {
  135. return STATUS_SUCCESS;
  136. } else {
  137. return STATUS_UNSUCCESSFUL;
  138. }
  139. }
  140. NTSTATUS
  141. esp_3_desdecrypt (
  142. PVOID pState,
  143. PUCHAR pOut,
  144. PUCHAR pIn,
  145. PUCHAR pIV
  146. )
  147. {
  148. DES3TABLE *Table = &((PCONF_STATE_BUFFER)pState)->des3Table;
  149. if (IPSEC_CBC(IPSEC_3DES_ALGO,
  150. pOut,
  151. pIn, // pChunk,
  152. Table,
  153. DECRYPT,
  154. pIV)) {
  155. return STATUS_SUCCESS;
  156. } else {
  157. return STATUS_UNSUCCESSFUL;
  158. }
  159. }
  160. IPRcvBuf *
  161. CopyToRcvBuf(
  162. IN IPRcvBuf *DestBuf,
  163. IN PUCHAR SrcBuf,
  164. IN ULONG Size,
  165. IN PULONG StartOffset
  166. )
  167. /*++
  168. Copy a flat buffer to an IPRcvBuf chain.
  169. A utility function to copy a flat buffer to an NDIS buffer chain. We
  170. assume that the NDIS_BUFFER chain is big enough to hold the copy amount;
  171. in a debug build we'll debugcheck if this isn't true. We return a pointer
  172. to the buffer where we stopped copying, and an offset into that buffer.
  173. This is useful for copying in pieces into the chain.
  174. Input:
  175. DestBuf - Destination IPRcvBuf chain.
  176. SrcBuf - Src flat buffer.
  177. Size - Size in bytes to copy.
  178. StartOffset - Pointer to start of offset into first buffer in
  179. chain. Filled in on return with the offset to
  180. copy into next.
  181. Returns:
  182. Pointer to next buffer in chain to copy into.
  183. --*/
  184. {
  185. UINT CopySize;
  186. UCHAR *DestPtr;
  187. UINT DestSize;
  188. UINT Offset = *StartOffset;
  189. UCHAR *VirtualAddress;
  190. UINT Length;
  191. if (DestBuf == NULL || SrcBuf == NULL) {
  192. ASSERT(FALSE);
  193. return NULL;
  194. }
  195. IPSecQueryRcvBuf(DestBuf, &VirtualAddress, &Length);
  196. ASSERT(Length >= Offset);
  197. DestPtr = VirtualAddress + Offset;
  198. DestSize = Length - Offset;
  199. for (;;) {
  200. CopySize = MIN(Size, DestSize);
  201. RtlCopyMemory(DestPtr, SrcBuf, CopySize);
  202. DestPtr += CopySize;
  203. SrcBuf += CopySize;
  204. if ((Size -= CopySize) == 0)
  205. break;
  206. if ((DestSize -= CopySize) == 0) {
  207. DestBuf = IPSEC_BUFFER_LINKAGE(DestBuf);
  208. if (DestBuf == NULL) {
  209. ASSERT(FALSE);
  210. break;
  211. }
  212. IPSecQueryRcvBuf(DestBuf, &VirtualAddress, &Length);
  213. DestPtr = VirtualAddress;
  214. DestSize = Length;
  215. }
  216. }
  217. *StartOffset = (ULONG)(DestPtr - VirtualAddress);
  218. return DestBuf;
  219. }
  220. NTSTATUS
  221. IPSecEncryptBuffer(
  222. IN PVOID pData,
  223. IN PNDIS_BUFFER *ppNewMdl,
  224. IN PSA_TABLE_ENTRY pSA,
  225. IN PNDIS_BUFFER pPadBuf,
  226. OUT PULONG pPadLen,
  227. IN ULONG PayloadType,
  228. IN ULONG Index,
  229. IN PUCHAR feedback
  230. )
  231. {
  232. CONF_STATE_BUFFER Key;
  233. PCONFID_ALGO pConfAlgo;
  234. UCHAR scratch[MAX_BLOCKLEN]; // scratch buffer for the encrypt
  235. UCHAR scratch1[MAX_BLOCKLEN]; // scratch buffer for the encrypt
  236. PUCHAR pDest=NULL;
  237. PNDIS_BUFFER pEncryptMdl;
  238. ULONG len;
  239. ULONG blockLen;
  240. NTSTATUS status, dummystatus;
  241. IPSEC_DEBUG(LL_A, DBF_ESP, ("Entering IPSecEncryptBuffer: pData: %p", pData));
  242. if (pSA->CONF_ALGO(Index) > NUM_CONF_ALGOS) {
  243. ASSERT(FALSE);
  244. return STATUS_INVALID_PARAMETER;
  245. }
  246. pConfAlgo = &(conf_algorithms[pSA->CONF_ALGO(Index)]);
  247. blockLen = pConfAlgo->blocklen;
  248. //
  249. // set up the state buffer
  250. //
  251. pConfAlgo->init((PVOID)&Key, pSA->CONF_KEY(Index));
  252. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("pConfAlgo: %p, blockLen: %lx IV: %lx-%lx", pConfAlgo, blockLen, *(PULONG)&feedback[0], *(PULONG)&feedback[4]));
  253. if (*ppNewMdl == NULL) {
  254. //
  255. // We should not encrypt in place: so we alloc a new buffer
  256. // Count up the total size and allocate the new buffer.
  257. // use that buffer as the dest of the encrypt.
  258. //
  259. IPSEC_GET_TOTAL_LEN(pData, &len);
  260. #if DBG
  261. if ((len % 8) != 0) {
  262. DbgPrint("Length not kosher: pData: %p, len: %d, pPadBuf: %p, pPadLen: %d", pData, len, pPadBuf, pPadLen);
  263. DbgBreakPoint();
  264. }
  265. #endif
  266. IPSecAllocateBuffer(&status, &pEncryptMdl, &pDest, len, IPSEC_TAG_ESP);
  267. if (!NT_SUCCESS(status)) {
  268. NTSTATUS ntstatus;
  269. //ASSERT(FALSE);
  270. IPSEC_DEBUG(LL_A, DBF_ESP, ("Failed to alloc. encrypt MDL"));
  271. return status;
  272. }
  273. IPSEC_DEBUG(LL_A, DBF_ESP, ("Alloc. MDL: %p, pDest: %p, len: %d, pData: %p", pEncryptMdl, pDest, len, pData));
  274. } else {
  275. ASSERT(FALSE);
  276. IPSecQueryNdisBuf(*ppNewMdl, &pDest, &len);
  277. pEncryptMdl = *ppNewMdl;
  278. }
  279. //
  280. // Now, send 64 bit (8 octet) chunks to CBC. We need to make sure
  281. // that the data is divided on contiguous 8 byte boundaries across
  282. // different buffers.
  283. //
  284. {
  285. PNDIS_BUFFER pBuf = (PNDIS_BUFFER)pData;
  286. ULONG bytesDone = 0;
  287. ULONG bytesLeft;
  288. PUCHAR pChunk;
  289. while (pBuf) {
  290. IPSecQueryNdisBuf(pBuf, &pChunk, &bytesLeft);
  291. pChunk += bytesDone;
  292. bytesLeft -= bytesDone;
  293. IPSEC_DEBUG(LL_A, DBF_ESP, ("ESP: pChunk: %p, bytesLeft: %d, bytesDone: %d", pChunk, bytesLeft, bytesDone));
  294. bytesDone = 0;
  295. while (bytesLeft >= blockLen) {
  296. //
  297. // Create the cipher.
  298. //
  299. status = pConfAlgo->encrypt( (PVOID)&Key,
  300. pDest,
  301. pChunk,
  302. feedback);
  303. if (!NT_SUCCESS(status)) {
  304. IPSecFreeBuffer(&dummystatus, pEncryptMdl);
  305. return status;
  306. }
  307. pChunk += blockLen;
  308. bytesLeft -= blockLen;
  309. pDest += blockLen;
  310. }
  311. //
  312. // Check here if we need to collate blocks
  313. //
  314. if (NDIS_BUFFER_LINKAGE(pBuf) != NULL) {
  315. PUCHAR pNextChunk;
  316. ULONG nextSize;
  317. //
  318. // If some left over from prev. buffer, collate with next
  319. // block
  320. //
  321. if (bytesLeft) {
  322. ULONG offset = bytesLeft; // offset into scratch
  323. ULONG bytesToCollect = blockLen - bytesLeft; // # of bytes to collect from next few MDLs
  324. IPSEC_DEBUG(LL_A, DBF_ESP, ("ESP: pChunk: %p, bytesLeft: %d", pChunk, bytesLeft));
  325. ASSERT(bytesLeft < blockLen);
  326. //
  327. // Copy into a scratch buffer
  328. //
  329. RtlCopyMemory( scratch,
  330. pChunk,
  331. bytesLeft);
  332. do {
  333. ASSERT(NDIS_BUFFER_LINKAGE(pBuf));
  334. IPSecQueryNdisBuf(NDIS_BUFFER_LINKAGE(pBuf), &pNextChunk, &nextSize);
  335. if (nextSize >= (blockLen - offset)) {
  336. RtlCopyMemory( scratch+offset,
  337. pNextChunk,
  338. blockLen - offset);
  339. bytesDone = blockLen - offset;
  340. bytesToCollect -= (blockLen - offset);
  341. ASSERT(bytesToCollect == 0);
  342. } else {
  343. IPSEC_DEBUG(LL_A, DBF_ESP, ("special case, offset: %d, bytesLeft: %d, nextSize: %d, pNextChunk: %p",
  344. offset, bytesLeft, nextSize, pNextChunk));
  345. RtlCopyMemory( scratch+offset,
  346. pNextChunk,
  347. nextSize);
  348. bytesToCollect -= nextSize;
  349. ASSERT(bytesToCollect);
  350. offset += nextSize;
  351. ASSERT(offset < blockLen);
  352. ASSERT(bytesDone == 0);
  353. pBuf = NDIS_BUFFER_LINKAGE(pBuf);
  354. }
  355. } while (bytesToCollect);
  356. status = pConfAlgo->encrypt( (PVOID)&Key,
  357. pDest,
  358. scratch,
  359. feedback);
  360. if (!NT_SUCCESS(status)) {
  361. IPSecFreeBuffer(&dummystatus, pEncryptMdl);
  362. return status;
  363. }
  364. pDest += blockLen;
  365. }
  366. } else {
  367. PUCHAR pPad;
  368. ULONG padLen;
  369. ULONG bufLen;
  370. //
  371. // End of the chain; pad with length and type to 8 byte boundary
  372. //
  373. ASSERT(bytesLeft < blockLen);
  374. // if ((pSA->sa_eOperation == HUGHES_TRANSPORT) ||
  375. // (pSA->sa_eOperation == HUGHES_TUNNEL)) {
  376. //
  377. // since only hughes is done now, this shd be always true.
  378. //
  379. if (TRUE) {
  380. ASSERT(bytesLeft == 0);
  381. //
  382. // DONE: break out
  383. //
  384. break;
  385. }
  386. }
  387. pBuf = NDIS_BUFFER_LINKAGE(pBuf);
  388. }
  389. //
  390. // save IV for next encrypt cycle
  391. //
  392. RtlCopyMemory( pSA->sa_iv[Index],
  393. feedback,
  394. pSA->sa_ivlen);
  395. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("IV: %lx-%lx", *(PULONG)&feedback[0], *(PULONG)&feedback[4]));
  396. }
  397. #if DBG
  398. {
  399. ULONG totalLen;
  400. IPSEC_GET_TOTAL_LEN(pEncryptMdl, &totalLen);
  401. ASSERT((totalLen % 8) == 0);
  402. IPSEC_DEBUG(LL_A, DBF_ESP, ("total len: %lx", totalLen));
  403. }
  404. #endif
  405. IPSEC_DEBUG(LL_A, DBF_ESP, ("Exiting IPSecEncryptBuffer"));
  406. *ppNewMdl = pEncryptMdl;
  407. return STATUS_SUCCESS;
  408. }
  409. NTSTATUS
  410. IPSecDecryptBuffer(
  411. IN PVOID pData,
  412. IN PSA_TABLE_ENTRY pSA,
  413. OUT PUCHAR pPadLen,
  414. OUT PUCHAR pPayloadType,
  415. IN ULONG Index,
  416. IN ULONG ESPOffset // offset from start of pData where ESP header starts
  417. )
  418. {
  419. CONF_STATE_BUFFER Key;
  420. PCONFID_ALGO pConfAlgo;
  421. UCHAR feedback[MAX_BLOCKLEN];
  422. UCHAR scratch[MAX_BLOCKLEN]; // scratch buffer for the encrypt
  423. UCHAR scratch1[MAX_BLOCKLEN]; // scratch buffer for the encrypt
  424. LONG Len;
  425. UCHAR padLen;
  426. UCHAR payloadType;
  427. LONG hdrLen;
  428. IPHeader UNALIGNED *pIPH;
  429. ESP UNALIGNED *pEsp;
  430. PUCHAR savePtr;
  431. LONG saveLen;
  432. LONG espLen = sizeof(ESP) + pSA->sa_ivlen + pSA->sa_ReplayLen + ESPOffset;
  433. LONG blockLen;
  434. NTSTATUS status;
  435. IPRcvBuf TmpRcvBuf;
  436. IPRcvBuf *pBuf,*SavedMdl=NULL;
  437. if (pSA->CONF_ALGO(Index) > NUM_CONF_ALGOS) {
  438. return STATUS_INVALID_PARAMETER;
  439. }
  440. pConfAlgo = &(conf_algorithms[pSA->CONF_ALGO(Index)]);
  441. blockLen = pConfAlgo->blocklen;
  442. //
  443. // set up the state buffer
  444. //
  445. pConfAlgo->init((PVOID)&Key, pSA->CONF_KEY(Index));
  446. IPSecQueryRcvBuf(pData, (PUCHAR)&pEsp, &Len);
  447. //
  448. // Init the CBC feedback from the IV in the packet
  449. //
  450. // Actually if the sa_ivlen is 0, use the pSA one
  451. //
  452. if (pSA->sa_ivlen) {
  453. if (Len >=(LONG)(sizeof(ESP) + pSA->sa_ReplayLen + pSA->sa_ivlen + ESPOffset)) {
  454. RtlCopyMemory( feedback,
  455. ((PUCHAR)(pEsp + 1) + pSA->sa_ReplayLen + ESPOffset),
  456. pSA->sa_ivlen);
  457. } else {
  458. status = IPSecGetRecvBytesByOffset(pData,
  459. sizeof(ESP)+pSA->sa_ReplayLen + ESPOffset,
  460. feedback,
  461. pSA->sa_ivlen);
  462. if (!NT_SUCCESS(status)) {
  463. return status;
  464. }
  465. }
  466. IPSEC_DEBUG(LL_A, DBF_ESP, ("IV: %lx-%lx", *(PULONG)&feedback[0], *(PULONG)&feedback[4]));
  467. } else {
  468. RtlCopyMemory( feedback,
  469. pSA->sa_iv[Index],
  470. DES_BLOCKLEN);
  471. }
  472. //
  473. // Bump the current pointer to after the ESP header
  474. //
  475. if (((IPRcvBuf *)pData)->ipr_size >= (ULONG)espLen) {
  476. ((IPRcvBuf *)pData)->ipr_size -= (ULONG)espLen;
  477. savePtr = ((IPRcvBuf *)pData)->ipr_buffer;
  478. saveLen = espLen;
  479. ((IPRcvBuf *)pData)->ipr_buffer = savePtr + espLen;
  480. } else {
  481. status = IPSecFindAndSetMdlByOffset((IPRcvBuf*)pData,(ULONG)espLen,&(IPRcvBuf*)pData,&savePtr,&saveLen);
  482. if (!NT_SUCCESS(status)) {
  483. return status;
  484. }
  485. }
  486. //
  487. // Now, send 64 bit (8 octet) chunks to CBC. We need to make sure
  488. // that the data is divided on contiguous 8 byte boundaries across
  489. // different buffers.
  490. // NOTE: the algo below assumes that there are a minimum of 8 bytes
  491. // per buffer in the chain.
  492. //
  493. {
  494. LONG bytesDone = 0;
  495. LONG bytesLeft;
  496. LONG saveBytesLeft;
  497. PUCHAR pChunk;
  498. PUCHAR pSaveChunk;
  499. pBuf=(IPRcvBuf *)pData;
  500. while (pBuf) {
  501. if (IPSEC_BUFFER_LEN(pBuf) == 0) {
  502. pBuf = IPSEC_BUFFER_LINKAGE(pBuf);
  503. continue;
  504. }
  505. IPSecQueryRcvBuf(pBuf, &pSaveChunk, &saveBytesLeft);
  506. bytesLeft = saveBytesLeft - bytesDone;
  507. pChunk = pSaveChunk + bytesDone;
  508. IPSEC_DEBUG(LL_A, DBF_ESP, ("ESP: 1.pChunk: %p, bytesLeft: %d, bytesDone: %d", pChunk, bytesLeft, bytesDone));
  509. bytesDone = 0;
  510. while (bytesLeft >= blockLen) {
  511. //
  512. // Decrypt the cipher.
  513. //
  514. status = pConfAlgo->decrypt( (PVOID)&Key,
  515. pChunk,
  516. pChunk,
  517. feedback);
  518. if (!NT_SUCCESS(status)) {
  519. return status;
  520. }
  521. pChunk += blockLen;
  522. bytesLeft -= blockLen;
  523. }
  524. IPSEC_DEBUG(LL_A, DBF_ESP, ("ESP: 2.pChunk: %p, bytesLeft: %d, bytesDone: %d", pChunk, bytesLeft, bytesDone));
  525. //
  526. // Check here if we need to collate blocks
  527. //
  528. if (IPSEC_BUFFER_LINKAGE(pBuf) != NULL) {
  529. PUCHAR pNextChunk;
  530. LONG nextSize;
  531. if (IPSEC_BUFFER_LEN(IPSEC_BUFFER_LINKAGE(pBuf)) == 0) {
  532. pBuf = IPSEC_BUFFER_LINKAGE(pBuf);
  533. }
  534. //
  535. // If some left over from prev. buffer, collate with next
  536. // block
  537. //
  538. if (bytesLeft) {
  539. LONG offset = bytesLeft;
  540. IPSEC_DEBUG(LL_A, DBF_ESP, ("ESP: 3.pChunk: %p, bytesLeft: %d, bytesDone: %d", pChunk, bytesLeft, bytesDone));
  541. ASSERT(bytesLeft < blockLen);
  542. //
  543. // Copy into a scratch buffer
  544. //
  545. RtlCopyMemory( scratch,
  546. pChunk,
  547. bytesLeft);
  548. IPSecQueryRcvBuf(IPSEC_BUFFER_LINKAGE(pBuf), &pNextChunk, &nextSize);
  549. if (nextSize >= (blockLen - bytesLeft)) {
  550. //
  551. // Copy remaining bytes into scratch
  552. //
  553. RtlCopyMemory( scratch+bytesLeft,
  554. pNextChunk,
  555. blockLen - bytesLeft);
  556. status = pConfAlgo->decrypt( (PVOID)&Key,
  557. scratch,
  558. scratch,
  559. feedback);
  560. if (!NT_SUCCESS(status)) {
  561. return status;
  562. }
  563. //
  564. // Copy cipher back into the payload
  565. //
  566. RtlCopyMemory( pChunk,
  567. scratch,
  568. bytesLeft);
  569. RtlCopyMemory( pNextChunk,
  570. scratch+bytesLeft,
  571. blockLen - bytesLeft);
  572. bytesDone = blockLen - bytesLeft;
  573. } else {
  574. //
  575. // Ugh! Collect the remaining bytes from the chain and redistribute them
  576. // after the decryption.
  577. //
  578. LONG bytesToCollect = blockLen - bytesLeft; // # of bytes to collect from next few MDLs
  579. IPRcvBuf *pFirstBuf = IPSEC_BUFFER_LINKAGE(pBuf); // to know where to start the distribution post decryption
  580. do {
  581. ASSERT(IPSEC_BUFFER_LINKAGE(pBuf));
  582. IPSecQueryRcvBuf(IPSEC_BUFFER_LINKAGE(pBuf), &pNextChunk, &nextSize);
  583. if (nextSize >= (blockLen - offset)) {
  584. RtlCopyMemory( scratch+offset,
  585. pNextChunk,
  586. blockLen - offset);
  587. bytesDone = blockLen - offset;
  588. bytesToCollect -= (blockLen - offset);
  589. ASSERT(bytesToCollect == 0);
  590. } else {
  591. IPSEC_DEBUG(LL_A, DBF_ESP, ("special case, offset: %d, bytesLeft: %d, nextSize: %d, pNextChunk: %p",
  592. offset, bytesLeft, nextSize, pNextChunk));
  593. RtlCopyMemory( scratch+offset,
  594. pNextChunk,
  595. nextSize);
  596. bytesToCollect -= nextSize;
  597. ASSERT(bytesToCollect);
  598. offset += nextSize;
  599. ASSERT(offset < blockLen);
  600. ASSERT(bytesDone == 0);
  601. pBuf = IPSEC_BUFFER_LINKAGE(pBuf);
  602. }
  603. } while (bytesToCollect);
  604. status = pConfAlgo->decrypt( (PVOID)&Key,
  605. scratch,
  606. scratch,
  607. feedback);
  608. if (!NT_SUCCESS(status)) {
  609. return status;
  610. }
  611. //
  612. // Now distribute the bytes back to the MDLs
  613. //
  614. RtlCopyMemory( pChunk,
  615. scratch,
  616. bytesLeft);
  617. pBuf = CopyToRcvBuf(pFirstBuf,
  618. scratch+bytesLeft,
  619. blockLen - bytesLeft,
  620. &bytesDone);
  621. continue;
  622. }
  623. }
  624. } else {
  625. //
  626. // end of chain.
  627. // should never come here with bytes left over since the
  628. // sender should pad to 8 byte boundary.
  629. //
  630. ASSERT(bytesLeft == 0);
  631. IPSEC_DEBUG(LL_A, DBF_ESP, ("ESP: 4.pChunk: %p, saveBytesLeft: %d, bytesDone: %d", pChunk, saveBytesLeft, bytesDone));
  632. IPSEC_DEBUG(LL_A, DBF_ESP, ("ESP: HUGHES: will remove pad later"));
  633. break;
  634. }
  635. pBuf = (IPRcvBuf *)IPSEC_BUFFER_LINKAGE(pBuf);
  636. }
  637. }
  638. //
  639. // Restore the first MDL
  640. //
  641. ((IPRcvBuf *)pData)->ipr_size += saveLen;
  642. ((IPRcvBuf *)pData)->ipr_buffer = savePtr;
  643. return STATUS_SUCCESS;
  644. }
  645. NTSTATUS
  646. IPSecFindAndSetMdlByOffset(IN IPRcvBuf *pData,
  647. IN ULONG Offset,
  648. OUT IPRcvBuf **OutMdl,
  649. OUT PUCHAR *savePtr,
  650. OUT PLONG saveLen)
  651. {
  652. ULONG TotalStartOffset=0; //Total start offset into data thus far
  653. BYTE *pBuffer;
  654. ULONG CurBufLen;
  655. while (pData) {
  656. IPSecQueryRcvBuf(pData,&pBuffer,&CurBufLen);
  657. if (Offset < CurBufLen+TotalStartOffset) {
  658. // Make the OutMdl start from the given offset
  659. *OutMdl=pData;
  660. *saveLen=(Offset - TotalStartOffset);
  661. *savePtr=pData->ipr_buffer;
  662. (*OutMdl)->ipr_size -= (Offset - TotalStartOffset);
  663. (*OutMdl)->ipr_buffer += (Offset - TotalStartOffset);
  664. return STATUS_SUCCESS;
  665. }
  666. TotalStartOffset +=CurBufLen;
  667. pData=IPSEC_BUFFER_LINKAGE(pData);
  668. }
  669. return STATUS_UNSUCCESSFUL;
  670. }