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.

1694 lines
54 KiB

  1. /*++
  2. Copyright (c) 1997-2001 Microsoft Corporation
  3. Module Name:
  4. hughes.c
  5. Abstract:
  6. This module contains the code to create/verify the Hughes transform.
  7. Author:
  8. Sanjay Anand (SanjayAn) 13-March-1997
  9. ChunYe
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. --*/
  14. #include "precomp.h"
  15. #ifdef RUN_WPP
  16. #include "hughes.tmh"
  17. #endif
  18. NTSTATUS
  19. IPSecHashMdlChainSend(
  20. IN PSA_TABLE_ENTRY pSA,
  21. IN PVOID pBuffer,
  22. IN PUCHAR pHash,
  23. IN AH_ALGO eAlgo,
  24. OUT PULONG pLen,
  25. IN ULONG Index,
  26. IN ULONG StartOffset
  27. )
  28. /*++
  29. Routine Description:
  30. Hash the entire chain using the algo passed in
  31. Arguments:
  32. pSA - the security association
  33. pBuffer - chain of MDLs (if fIncoming is FALSE) or RcvBufs (if fIncoming is TRUE)
  34. pHash - where to put the hash
  35. fIncoming - TRUE if on recv path
  36. eAlgo - the algorithm index
  37. pLen - returns length hashed
  38. StartOffset - offset from start from which to start hashing
  39. Return Value:
  40. STATUS_SUCCESS
  41. Others:
  42. STATUS_INSUFFICIENT_RESOURCES
  43. STATUS_UNSUCCESSFUL (error in algo.)
  44. --*/
  45. {
  46. ALGO_STATE State = {0};
  47. NTSTATUS status;
  48. PAUTH_ALGO pAlgo=&(auth_algorithms[eAlgo]);
  49. PUCHAR pPyld;
  50. ULONG Len=0,TmpLen=0;
  51. ULONG CurOffset=0;
  52. PNDIS_BUFFER pBuf = (PNDIS_BUFFER)pBuffer;
  53. State.as_sa = pSA;
  54. status = pAlgo->init(&State, Index);
  55. if (StartOffset == 0) {
  56. while (pBuf) {
  57. IPSecQueryNdisBuf(pBuf, &pPyld, &Len);
  58. pAlgo->update(&State, pPyld, Len);
  59. *pLen += Len;
  60. pBuf = NDIS_BUFFER_LINKAGE(pBuf);
  61. }
  62. } else {
  63. // gotta get to correct offset before starting hash
  64. if (pBuf) {
  65. IPSecQueryNdisBuf(pBuf, &pPyld, &Len);
  66. }
  67. // walk to StartOffset
  68. while (pBuf && Len + CurOffset < StartOffset) {
  69. CurOffset += Len;
  70. pBuf = NDIS_BUFFER_LINKAGE(pBuf);
  71. if (pBuf) {
  72. IPSecQueryNdisBuf(pBuf, &pPyld, &Len);
  73. }
  74. }
  75. while (pBuf) {
  76. IPSecQueryNdisBuf(pBuf, &pPyld, &Len);
  77. if (StartOffset > CurOffset) {
  78. pPyld += (StartOffset - CurOffset);
  79. TmpLen = Len-(StartOffset - CurOffset);
  80. } else {
  81. TmpLen = Len;
  82. }
  83. pAlgo->update(&State, pPyld, TmpLen);
  84. *pLen += TmpLen;
  85. CurOffset += Len;
  86. pBuf = NDIS_BUFFER_LINKAGE(pBuf);
  87. }
  88. }
  89. pAlgo->finish(&State, pHash, Index);
  90. return STATUS_SUCCESS;
  91. }
  92. NTSTATUS
  93. IPSecHashMdlChainRecv(
  94. IN PSA_TABLE_ENTRY pSA,
  95. IN PVOID pBuffer,
  96. IN PUCHAR pHash,
  97. IN AH_ALGO eAlgo,
  98. OUT PULONG pLen,
  99. IN ULONG Index,
  100. IN ULONG StartOffset
  101. )
  102. /*++
  103. Routine Description:
  104. Hash the entire chain using the algo passed in
  105. Arguments:
  106. pSA - the security association
  107. pBuffer - chain of MDLs (if fIncoming is FALSE) or RcvBufs (if fIncoming is TRUE)
  108. pHash - where to put the hash
  109. fIncoming - TRUE if on recv path
  110. eAlgo - the algorithm index
  111. pLen - returns length hashed
  112. StartOffset - offset from start from which to start hashing
  113. Return Value:
  114. STATUS_SUCCESS
  115. Others:
  116. STATUS_INSUFFICIENT_RESOURCES
  117. STATUS_UNSUCCESSFUL (error in algo.)
  118. --*/
  119. {
  120. ALGO_STATE State = {0};
  121. NTSTATUS status;
  122. PAUTH_ALGO pAlgo=&(auth_algorithms[eAlgo]);
  123. PUCHAR pPyld;
  124. ULONG Len=0,TmpLen=0;
  125. IPRcvBuf *pBuf = (IPRcvBuf *)pBuffer;
  126. ULONG CurOffset=0;
  127. State.as_sa = pSA;
  128. status = pAlgo->init(&State, Index);
  129. if (StartOffset == 0) {
  130. // Hash it all
  131. while (pBuf) {
  132. IPSecQueryRcvBuf(pBuf, &pPyld, &Len);
  133. pAlgo->update(&State, pPyld, Len);
  134. *pLen += Len;
  135. pBuf = IPSEC_BUFFER_LINKAGE(pBuf);
  136. }
  137. } else {
  138. // gotta get to correct offset before starting hash
  139. if (pBuf) {
  140. IPSecQueryRcvBuf(pBuf, &pPyld, &Len);
  141. }
  142. // walk to StartOffset
  143. while (pBuf && Len + CurOffset < StartOffset) {
  144. CurOffset += Len;
  145. pBuf = IPSEC_BUFFER_LINKAGE(pBuf);
  146. if (pBuf) {
  147. IPSecQueryRcvBuf(pBuf, &pPyld, &Len);
  148. }
  149. }
  150. while (pBuf) {
  151. IPSecQueryRcvBuf(pBuf, &pPyld, &Len);
  152. if (StartOffset > CurOffset) {
  153. pPyld += (StartOffset - CurOffset);
  154. TmpLen = Len-(StartOffset - CurOffset);
  155. } else {
  156. TmpLen = Len;
  157. }
  158. pAlgo->update(&State, pPyld, TmpLen);
  159. *pLen += TmpLen;
  160. CurOffset += Len;
  161. pBuf = IPSEC_BUFFER_LINKAGE(pBuf);
  162. }
  163. }
  164. pAlgo->finish(&State, pHash, Index);
  165. return STATUS_SUCCESS;
  166. }
  167. NTSTATUS
  168. IPSecCreateHughes(
  169. IN PUCHAR pIPHeader,
  170. IN PVOID pData,
  171. IN PVOID IPContext,
  172. IN PSA_TABLE_ENTRY pSA,
  173. IN ULONG Index,
  174. OUT PVOID *ppNewData,
  175. OUT PVOID *ppSCContext,
  176. OUT PULONG pExtraBytes,
  177. IN ULONG HdrSpace,
  178. IN PNDIS_PACKET pNdisPacket,
  179. IN BOOLEAN fCryptoOnly
  180. )
  181. /*++
  182. Routine Description:
  183. Create the combined esp-des-* transform, as outlined in
  184. draft-ietf-ipsec-esp-v2-00, on the send side.
  185. 0 1 2 3
  186. 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  187. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ----
  188. | Security Parameters Index (SPI) | ^
  189. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Auth.
  190. | Sequence Number | |Coverage
  191. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | -----
  192. | Payload Data* (variable) | | ^
  193. ~ ~ | |
  194. | | | |
  195. + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Confid.
  196. | | Padding (0-255 bytes) | |Coverage*
  197. +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
  198. | | Pad Length | Next Header | v v
  199. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -------
  200. | Authentication Data (variable) |
  201. ~ ~
  202. | |
  203. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  204. * If included in the Payload field, cryptographic synchronization
  205. data, e.g., an IV, usually is not encrypted per se, although it
  206. often is referred to as being part of the ciphertext.
  207. The payload field, as defined in [ESP], is broken down according to
  208. the following diagram:
  209. +---------------+---------------+---------------+---------------+
  210. | |
  211. + Initialization Vector (IV) +
  212. | |
  213. +---------------+---------------+---------------+---------------+
  214. | |
  215. ~ Encrypted Payload (variable length) ~
  216. | |
  217. +---------------------------------------------------------------+
  218. 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
  219. Arguments:
  220. pIPHeader - points to start of IP header.
  221. pData - points to the data after the IP header. PNDIS_BUFFER
  222. pSA - Sec. Assoc. entry
  223. ppNewData - the new MDL chain to be used by TCPIP
  224. ppSCContext - send complete context used to clean up IPSEC headers
  225. pExtraBytes - the header expansion caused by this IPSEC header
  226. Return Value:
  227. STATUS_SUCCESS
  228. Others:
  229. STATUS_INSUFFICIENT_RESOURCES
  230. STATUS_UNSUCCESSFUL (error in algo.)
  231. --*/
  232. {
  233. ESP UNALIGNED *pESP;
  234. VOID UNALIGNED *pTmpNat;
  235. NATENCAP UNALIGNED *pNat;
  236. NATENCAP_OTHER UNALIGNED *pNatOther;
  237. NTSTATUS status = STATUS_SUCCESS;
  238. PNDIS_BUFFER pESPBuffer = NULL;
  239. PNDIS_BUFFER pPadBuf = NULL;
  240. PNDIS_BUFFER pOptBuf = NULL;
  241. ULONG espLen;
  242. ULONG padLen;
  243. ULONG totalLen = 0;
  244. IPHeader UNALIGNED * pIPH;
  245. PIPSEC_SEND_COMPLETE_CONTEXT pContext;
  246. PNDIS_BUFFER pNewMdl = NULL;
  247. PNDIS_BUFFER pSaveMdl;
  248. PAUTH_ALGO pAlgo = &(auth_algorithms[pSA->INT_ALGO(Index)]);
  249. ULONG PayloadType;
  250. ULONG hdrLen;
  251. PUCHAR pPad;
  252. ULONG TruncatedLen = (pSA->INT_ALGO(Index) != IPSEC_AH_NONE)? pSA->sa_TruncatedLen: 0;
  253. BOOLEAN fTunnel = ( (pSA->sa_Flags & FLAGS_SA_TUNNEL) &&
  254. ((Index == 0) ||
  255. ((Index == 1) && (pSA->sa_Operation[0] == Compress))));
  256. ULONG tag = (!fTunnel) ?
  257. IPSEC_TAG_HUGHES :
  258. IPSEC_TAG_HUGHES_TU;
  259. IPHeader UNALIGNED * pIPH2;
  260. PNDIS_BUFFER pHdrBuf=NULL;
  261. ULONG bytesLeft;
  262. ULONG hashBytes=0;
  263. ULONG saveFlags=0;
  264. ULONG Seq;
  265. USHORT IPLength;
  266. PNDIS_BUFFER pSaveDataLinkage = NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData);
  267. PNDIS_BUFFER pSaveOptLinkage = NULL;
  268. PNDIS_BUFFER pSaveBeforePad = NULL;
  269. PIPSEC_MTU_CONTEXT pMTUContext=NULL;
  270. ULONG ExtraTransportNat=0;
  271. BOOLEAN bNATEncap = FALSE;
  272. Interface * DestIF = (Interface *) IPContext;
  273. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Entering IPSecCreateHughes"));
  274. #if DBG
  275. IPSEC_DEBUG(LL_A, DBF_MDL, ("Entering IPSecCreateHughes"));
  276. IPSEC_PRINT_CONTEXT(*ppSCContext);
  277. IPSEC_PRINT_MDL(pData);
  278. #endif
  279. ASSERT(pSA->sa_Operation[Index] == Encrypt);
  280. if (*ppSCContext == NULL) {
  281. pContext = IPSecAllocateSendCompleteCtx(tag);
  282. if (!pContext) {
  283. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Failed to alloc. SendCtx"));
  284. return STATUS_INSUFFICIENT_RESOURCES;
  285. }
  286. IPSEC_INCREMENT(g_ipsec.NumSends);
  287. IPSecZeroMemory(pContext, sizeof(IPSEC_SEND_COMPLETE_CONTEXT));
  288. #if DBG
  289. RtlCopyMemory(pContext->Signature, "ISC4", 4);
  290. #endif
  291. //
  292. // Send complete context
  293. //
  294. *ppSCContext = pContext;
  295. } else {
  296. pContext = *ppSCContext;
  297. saveFlags = pContext->Flags;
  298. }
  299. //
  300. // get the pad len -> total length + replay prevention field len + padlen + payloadtype needs to be padded to
  301. // 8 byte boundary.
  302. //
  303. pIPH = (IPHeader UNALIGNED *)pIPHeader;
  304. hdrLen = (pIPH->iph_verlen & (UCHAR)~IP_VER_FLAG) << 2;
  305. //
  306. // Transport mode: payload is after IP header => payloadlen is total len - hdr len
  307. // Tunnel modes: payload starts at IP header => payloadlen is total len
  308. //
  309. totalLen = (!fTunnel) ?
  310. NET_SHORT(pIPH->iph_length) - hdrLen :
  311. NET_SHORT(pIPH->iph_length);
  312. if ((pSA->CONF_ALGO(Index) == IPSEC_ESP_NONE) || fCryptoOnly) {
  313. if (fTunnel) {
  314. pContext->Flags |= SCF_NOE_TU;
  315. } else {
  316. pContext->Flags |= SCF_NOE_TPT;
  317. }
  318. }
  319. {
  320. PCONFID_ALGO pConfAlgo;
  321. ULONG blockLen;
  322. pConfAlgo = &(conf_algorithms[pSA->CONF_ALGO(Index)]);
  323. blockLen = pConfAlgo->blocklen;
  324. bytesLeft = (totalLen) % blockLen;
  325. if (bytesLeft <= blockLen - NUM_EXTRA) {
  326. //
  327. // we can now fit the leftover + Pad length + Payload Type in a single
  328. // chunk
  329. //
  330. padLen = blockLen - bytesLeft;
  331. } else {
  332. //
  333. // we pad the bytesleft to next octet boundary, then attach the length/type
  334. //
  335. padLen = (blockLen << 1) - bytesLeft;
  336. }
  337. }
  338. //
  339. // Get buffer for trailing PAD and signature (MD5 signature len)
  340. //
  341. IPSecAllocateBuffer(&status,
  342. &pPadBuf,
  343. &pPad,
  344. padLen + pAlgo->OutputLen,
  345. tag);
  346. if (!NT_SUCCESS(status)) {
  347. NTSTATUS ntstatus;
  348. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Failed to alloc. PAD MDL"));
  349. pContext->Flags = saveFlags;
  350. return status;
  351. }
  352. //
  353. // the padding should contain 1, 2, 3, 4.... (latest ESP draft - draft-ietf-ipsec-esp-v2-02.txt)
  354. // for any algo that doesn't specify its own padding - right now all implemented algos go with
  355. // the default.
  356. //
  357. RtlCopyMemory(pPad, DefaultPad, padLen);
  358. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("IP Len: %lx, pPad: %p, PadLen: %lx", NET_SHORT(pIPH->iph_length), pPad, padLen));
  359. //
  360. // Link in the pad buffer at end of the data chain
  361. //
  362. {
  363. PNDIS_BUFFER temp = pData;
  364. while (NDIS_BUFFER_LINKAGE(temp)) {
  365. temp = NDIS_BUFFER_LINKAGE(temp);
  366. }
  367. NDIS_BUFFER_LINKAGE(temp) = pPadBuf;
  368. pSaveBeforePad = temp;
  369. if (fTunnel) {
  370. pContext->BeforePadTuMdl = temp;
  371. pContext->PadTuMdl = pPadBuf;
  372. } else {
  373. pContext->BeforePadMdl = temp;
  374. pContext->PadMdl = pPadBuf;
  375. }
  376. }
  377. NDIS_BUFFER_LINKAGE(pPadBuf) = NULL;
  378. switch(pSA->sa_EncapType) {
  379. case SA_UDP_ENCAP_TYPE_NONE:
  380. break;
  381. case SA_UDP_ENCAP_TYPE_IKE:
  382. ExtraTransportNat= sizeof(NATENCAP);
  383. break;
  384. case SA_UDP_ENCAP_TYPE_OTHER:
  385. ExtraTransportNat=sizeof(NATENCAP_OTHER);
  386. break;
  387. }
  388. espLen = sizeof(ESP) + pSA->sa_ivlen + pSA->sa_ReplayLen + ExtraTransportNat;
  389. //
  390. // Get buffer for Hughes header
  391. //
  392. IPSecAllocateBuffer(&status,
  393. &pESPBuffer,
  394. (PUCHAR *)&pESP,
  395. espLen,
  396. tag);
  397. if (!NT_SUCCESS(status)) {
  398. NTSTATUS ntstatus;
  399. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Failed to alloc. ESP MDL"));
  400. NDIS_BUFFER_LINKAGE(pSaveBeforePad) = NULL;
  401. IPSecFreeBuffer(&ntstatus, pPadBuf);
  402. pContext->Flags = saveFlags;
  403. return status;
  404. }
  405. if (pSA->sa_EncapType == SA_UDP_ENCAP_TYPE_IKE ||
  406. pSA->sa_EncapType == SA_UDP_ENCAP_TYPE_OTHER) {
  407. pTmpNat=pESP;
  408. pESP=(ESP*)(((PUCHAR)pESP)+ExtraTransportNat);
  409. // Alloc MTU adjust context
  410. if (!pContext->pMTUContext) {
  411. pContext->pMTUContext=IPSecAllocateMemory(sizeof(IPSEC_MTU_CONTEXT),IPSEC_TAG_SEND_COMPLETE);
  412. }
  413. pMTUContext=pContext->pMTUContext;
  414. if (pMTUContext) {
  415. IPSecZeroMemory(pMTUContext,sizeof(IPSEC_MTU_CONTEXT));
  416. pContext->Flags |= SCF_MTU;
  417. saveFlags |= SCF_MTU;
  418. pMTUContext->Src = pIPH->iph_src;
  419. if (fTunnel) {
  420. pMTUContext->TunnelSPI = HOST_TO_NET_LONG(pSA->sa_OtherSPIs[Index]);
  421. pMTUContext->TunnelDest = pSA->sa_TunnelAddr;
  422. } else {
  423. pMTUContext->TransportSPI = HOST_TO_NET_LONG(pSA->sa_OtherSPIs[Index]);
  424. pMTUContext->TransportDest = pIPH->iph_dest;
  425. }
  426. }
  427. }
  428. if (fTunnel) {
  429. PNDIS_BUFFER pSrcOptBuf;
  430. PUCHAR pOpt;
  431. PUCHAR pSrcOpt;
  432. ULONG optLen = 0;
  433. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Hughes Tunnel mode..."));
  434. //
  435. // Allocate an MDL for the new cleartext IP header
  436. //
  437. IPSecAllocateBuffer(&status,
  438. &pHdrBuf,
  439. (PUCHAR *)&pIPH2,
  440. sizeof(IPHeader),
  441. IPSEC_TAG_AH);
  442. if (!NT_SUCCESS(status)) {
  443. NTSTATUS ntstatus;
  444. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Failed to alloc. PAD MDL"));
  445. NDIS_BUFFER_LINKAGE(pSaveBeforePad) = NULL;
  446. IPSecFreeBuffer(&ntstatus, pPadBuf);
  447. IPSecFreeBuffer(&ntstatus, pESPBuffer);
  448. pContext->Flags = saveFlags;
  449. return status;
  450. }
  451. *pExtraBytes += espLen + padLen + TruncatedLen + sizeof(IPHeader);
  452. //
  453. // Now hookup the MDLs
  454. //
  455. pContext->Flags |= SCF_HU_TU;
  456. pContext->HUTuMdl = pESPBuffer;
  457. pContext->PrevTuMdl = (PNDIS_BUFFER)pData;
  458. pContext->HUHdrMdl = pHdrBuf;
  459. pContext->OriTuMdl = NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData);
  460. NDIS_BUFFER_LINKAGE(pESPBuffer) = pHdrBuf;
  461. if (hdrLen > sizeof(IPHeader)) {
  462. if (HdrSpace < *pExtraBytes) {
  463. IPSEC_DEBUG(LL_A, DBF_AH, ("Going to frag."));
  464. pSrcOptBuf = NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData);
  465. pSaveOptLinkage = NDIS_BUFFER_LINKAGE(pSrcOptBuf);
  466. IPSecQueryNdisBuf(pSrcOptBuf, &pSrcOpt, &optLen);
  467. IPSecAllocateBuffer(&status,
  468. &pOptBuf,
  469. (PUCHAR *)&pOpt,
  470. hdrLen - sizeof(IPHeader),
  471. IPSEC_TAG_AH);
  472. if (!NT_SUCCESS(status)) {
  473. NTSTATUS ntstatus;
  474. IPSEC_DEBUG(LL_A, DBF_AH, ("Failed to alloc. PAD MDL"));
  475. NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData) = pSaveDataLinkage;
  476. NDIS_BUFFER_LINKAGE(pSaveBeforePad) = NULL;
  477. IPSecFreeBuffer(&ntstatus, pESPBuffer);
  478. if (pHdrBuf) {
  479. IPSecFreeBuffer(&ntstatus, pHdrBuf);
  480. }
  481. IPSecFreeBuffer(&ntstatus, pPadBuf);
  482. pContext->Flags = saveFlags;
  483. return status;
  484. }
  485. RtlCopyMemory(pOpt, pSrcOpt, hdrLen-sizeof(IPHeader));
  486. pContext->OptMdl = pOptBuf;
  487. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Copying options. S: %p, D: %p", pSrcOptBuf, pOptBuf));
  488. //
  489. // replace the original Opt Mdl with ours.
  490. //
  491. NDIS_BUFFER_LINKAGE(pOptBuf) = NDIS_BUFFER_LINKAGE(pSrcOptBuf);
  492. NDIS_BUFFER_LINKAGE(pHdrBuf) = pOptBuf;
  493. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Options; pointed Hdrbuf: %p to pOptBuf: %p", pHdrBuf, pOptBuf));
  494. *pExtraBytes += hdrLen-sizeof(IPHeader);
  495. } else {
  496. NDIS_BUFFER_LINKAGE(pHdrBuf) = NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData);
  497. }
  498. } else {
  499. NDIS_BUFFER_LINKAGE(pHdrBuf) = NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData);
  500. }
  501. NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData) = pESPBuffer;
  502. //
  503. // xsum the new IP header since we expect that to be the case
  504. // at this stage in tpt mode.
  505. //
  506. RtlCopyMemory(pIPH2, pIPH, sizeof(IPHeader));
  507. //
  508. // no options in the outer header; reset the len.
  509. //
  510. pIPH->iph_verlen = IP_VERSION + (sizeof(IPHeader) >> 2);
  511. //
  512. // also reset the frag. params.
  513. //
  514. pIPH->iph_offset &= ~(IP_MF_FLAG | IP_OFFSET_MASK);
  515. if (DestIF->if_dfencap == ClearDfEncap) {
  516. pIPH->iph_offset &= ~(IP_DF_FLAG | IP_OFFSET_MASK);
  517. }
  518. ASSERT(pSA->sa_TunnelAddr);
  519. //
  520. // Tunnel starts here; replace dest addr to point to Tunnel end if specified
  521. // else tunnel ends at final dest
  522. //
  523. pIPH->iph_dest = pSA->sa_TunnelAddr;
  524. //
  525. // The first pended packet on a gateway (proxy negotiating for two subnets)
  526. // would come via the transmit path. Hence the source address would not be
  527. // kosher. We need to replace the src address in that case also.
  528. // We get this from the corresponding inbound SA's tunnel addr.
  529. //
  530. pIPH->iph_src = pSA->sa_SrcTunnelAddr;
  531. pIPH->iph_id = (ushort) TCPIP_GEN_IPID();
  532. pIPH->iph_xsum = 0;
  533. pIPH->iph_xsum = ~xsum(pIPH, sizeof(IPHeader));
  534. //
  535. // Set up headers so CreateHash works as in Tpt mode.
  536. //
  537. pIPHeader = (PUCHAR)pIPH;
  538. *ppNewData = pData;
  539. PayloadType = IP_IN_IP;
  540. } else {
  541. *pExtraBytes += espLen + padLen + TruncatedLen;
  542. if (hdrLen > sizeof(IPHeader)) {
  543. //
  544. // Options present - chain ESP after options
  545. //
  546. pSaveMdl = pContext->OriHUMdl = NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData));
  547. pContext->PrevMdl = NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData);
  548. NDIS_BUFFER_LINKAGE(pESPBuffer) = pContext->OriHUMdl;
  549. NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData)) = pESPBuffer;
  550. pContext->Flags |= SCF_HU_TPT;
  551. } else {
  552. //
  553. // Chain the ESP buffer after IP header
  554. //
  555. pSaveMdl = pContext->OriHUMdl = NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData);
  556. pContext->PrevMdl = (PNDIS_BUFFER)pData;
  557. NDIS_BUFFER_LINKAGE(pESPBuffer) = pContext->OriHUMdl;
  558. NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData) = pESPBuffer;
  559. pContext->Flags |= SCF_HU_TPT;
  560. }
  561. //
  562. // Save the MDL pointer so we can hook it in place on SendComplete
  563. //
  564. pContext->HUMdl = pESPBuffer;
  565. PayloadType = ((UNALIGNED IPHeader *)pIPH)->iph_protocol;
  566. }
  567. //
  568. // Fill in the padlen at start of pad + padlen - NUM_EXTRA
  569. //
  570. *(pPad + padLen - NUM_EXTRA) = (UCHAR)padLen - NUM_EXTRA;
  571. //
  572. // Set the Payload Type
  573. //
  574. *(pPad + padLen + sizeof(UCHAR) - NUM_EXTRA) = (UCHAR)PayloadType;
  575. //
  576. // Initialize the other fields of the ESP header
  577. //
  578. pESP->esp_spi = HOST_TO_NET_LONG(pSA->sa_OtherSPIs[Index]);
  579. //
  580. // Copy the Replay field into the Hughes header
  581. //
  582. Seq = IPSEC_INCREMENT(pSA->sa_ReplaySendSeq[Index]);
  583. *(UNALIGNED ULONG *)(pESP + 1) = HOST_TO_NET_LONG(Seq);
  584. //IPSEC_DEBUG(LL_A, DBF_HUGHES, ("SPI %lx Seq &lx", pESP->esp_spi, HOST_TO_NET_LONG(Seq)));
  585. if ((pSA->CONF_ALGO(Index) != IPSEC_ESP_NONE) && !fCryptoOnly) {
  586. UCHAR feedback[MAX_BLOCKLEN];
  587. KIRQL kIrql;
  588. //
  589. // Pad is included in the chain, so prevent double free by NULL'ing
  590. // the ref.
  591. //
  592. if (fTunnel) {
  593. pContext->PadTuMdl = NULL;
  594. } else {
  595. pContext->PadMdl = NULL;
  596. }
  597. //
  598. // NOTE: The way the IV is supposed to work is that initially, the IV
  599. // is a random value. The IV is then updated with the residue of the
  600. // last encryption block of a packet. This is used as the starting IV
  601. // for the next block. This assures a fairly random IV sample and
  602. // introduces some notion of IV chaining.
  603. //
  604. // The only way for this to work is to make the entire encryption atomic,
  605. // which would be a performance drag. So, we take a less strict approach here.
  606. //
  607. // We just ensure that each packet starts at a random value, and also do the
  608. // chaining.
  609. //
  610. //
  611. // Copy the IV into the Hughes header
  612. //
  613. ACQUIRE_LOCK(&pSA->sa_Lock, &kIrql);
  614. RtlCopyMemory( ((PUCHAR)(pESP + 1) + pSA->sa_ReplayLen),
  615. pSA->sa_iv[Index],
  616. pSA->sa_ivlen);
  617. //
  618. // Init the CBC feedback
  619. //
  620. RtlCopyMemory( feedback,
  621. pSA->sa_iv[Index],
  622. DES_BLOCKLEN);
  623. IPSecGenerateRandom((PUCHAR)&pSA->sa_iv[Index][0], DES_BLOCKLEN);
  624. RELEASE_LOCK(&pSA->sa_Lock, kIrql);
  625. //
  626. // Encrypt the entire block, starting after the IV (if it exists)
  627. //
  628. //
  629. // Make it appear that pESPMdl points to after Replay field
  630. //
  631. NdisBufferLength((PNDIS_BUFFER)pESPBuffer) -= (sizeof(ESP) + pSA->sa_ivlen + pSA->sa_ReplayLen + ExtraTransportNat);
  632. (PUCHAR)((PNDIS_BUFFER)pESPBuffer)->MappedSystemVa += (sizeof(ESP) + pSA->sa_ivlen + pSA->sa_ReplayLen + ExtraTransportNat);
  633. //
  634. // Remove the Hash bytes since we dont want to encrypt them
  635. //
  636. NdisBufferLength((PNDIS_BUFFER)pPadBuf) -= pAlgo->OutputLen;
  637. ASSERT(NdisBufferLength((PNDIS_BUFFER)pESPBuffer) == 0);
  638. status = IPSecEncryptBuffer((PVOID)pESPBuffer,
  639. &pNewMdl,
  640. pSA,
  641. pPadBuf,
  642. &padLen,
  643. 0,
  644. Index,
  645. feedback);
  646. if (!NT_SUCCESS(status)) {
  647. NTSTATUS ntstatus;
  648. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Failed to encrypt, pESP: %p", pESP));
  649. //
  650. // Don't forget we need to restore ESP MDL since SystemVa has been
  651. // changed. If not, we have trouble later if the same buffer is
  652. // used during reinject since we use the buffer as a real MDL
  653. // there.
  654. //
  655. NdisBufferLength((PNDIS_BUFFER)pESPBuffer) += (sizeof(ESP) + pSA->sa_ivlen + pSA->sa_ReplayLen + ExtraTransportNat);
  656. (PUCHAR)((PNDIS_BUFFER)pESPBuffer)->MappedSystemVa -= (sizeof(ESP) + pSA->sa_ivlen + pSA->sa_ReplayLen + ExtraTransportNat);
  657. NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData) = pSaveDataLinkage;
  658. NDIS_BUFFER_LINKAGE(pSaveBeforePad) = NULL;
  659. if (pSaveOptLinkage) {
  660. NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData)) = pSaveOptLinkage;
  661. }
  662. IPSecFreeBuffer(&ntstatus, pESPBuffer);
  663. if (pHdrBuf) {
  664. IPSecFreeBuffer(&ntstatus, pHdrBuf);
  665. }
  666. if (pOptBuf) {
  667. IPSecFreeBuffer(&ntstatus, pOptBuf);
  668. }
  669. IPSecFreeBuffer(&ntstatus, pPadBuf);
  670. pContext->Flags = saveFlags;
  671. return status;
  672. }
  673. NdisBufferLength((PNDIS_BUFFER)pPadBuf) += pAlgo->OutputLen;
  674. NdisBufferLength((PNDIS_BUFFER)pESPBuffer) += (sizeof(ESP) + pSA->sa_ivlen + pSA->sa_ReplayLen + ExtraTransportNat);
  675. (PUCHAR)((PNDIS_BUFFER)pESPBuffer)->MappedSystemVa -= (sizeof(ESP) + pSA->sa_ivlen + pSA->sa_ReplayLen + ExtraTransportNat);
  676. NDIS_BUFFER_LINKAGE(pESPBuffer) = pNewMdl;
  677. //
  678. // HMAC the entire block - starting at the SPI field => start of pESPBuffer
  679. //
  680. status = IPSecHashMdlChainSend( pSA,
  681. (PVOID)pESPBuffer, // source
  682. pPad, // dest
  683. pSA->INT_ALGO(Index), // algo
  684. &hashBytes,
  685. Index,
  686. ExtraTransportNat);
  687. // Check return of HashMdlChain
  688. if (!NT_SUCCESS(status)) {
  689. NTSTATUS ntstatus;
  690. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Failed to hash, pAH: %p", pESP));
  691. NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData) = pSaveDataLinkage;
  692. NDIS_BUFFER_LINKAGE(pSaveBeforePad) = NULL;
  693. if (pSaveOptLinkage) {
  694. NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData)) = pSaveOptLinkage;
  695. }
  696. IPSecFreeBuffer(&ntstatus, pESPBuffer);
  697. if (pHdrBuf) {
  698. IPSecFreeBuffer(&ntstatus, pHdrBuf);
  699. }
  700. if (pOptBuf) {
  701. IPSecFreeBuffer(&ntstatus, pOptBuf);
  702. }
  703. IPSecFreeBuffer(&ntstatus, pPadBuf);
  704. IPSecFreeBuffer(&ntstatus, pNewMdl);
  705. pContext->Flags = saveFlags;
  706. return status;
  707. }
  708. //
  709. // hook up the pad mdl which contains the final hash (the pad mdl was copied into
  710. // newMdl returned by EncryptDESCBC). Also, set the length of the Pad mdl to hash len.
  711. //
  712. // Remember we need to truncate this to 96 bits, so make it appear
  713. // as if we have only 96 bits.
  714. //
  715. NdisBufferLength(pPadBuf) = TruncatedLen;
  716. NDIS_BUFFER_LINKAGE(pNewMdl) = pPadBuf;
  717. pNdisPacket->Private.Tail = pPadBuf;
  718. } else {
  719. //
  720. // HMAC the entire block - starting at the SPI field => start of pESPBuffer
  721. //
  722. //
  723. // Remove the Hash bytes since we dont want to hash them
  724. //
  725. if (!fCryptoOnly) {
  726. NdisBufferLength((PNDIS_BUFFER)pPadBuf) -= pAlgo->OutputLen;
  727. status = IPSecHashMdlChainSend( pSA,
  728. (PVOID)pESPBuffer, // source
  729. (PUCHAR)(pPad + padLen), // dest
  730. pSA->INT_ALGO(Index), // algo
  731. &hashBytes,
  732. Index,
  733. ExtraTransportNat);
  734. NdisBufferLength((PNDIS_BUFFER)pPadBuf) += pAlgo->OutputLen;
  735. if (!NT_SUCCESS(status)) {
  736. NTSTATUS ntstatus;
  737. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Failed to hash, pAH: %p", pESP));
  738. NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData) = pSaveDataLinkage;
  739. NDIS_BUFFER_LINKAGE(pSaveBeforePad) = NULL;
  740. if (pSaveOptLinkage) {
  741. NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData)) = pSaveOptLinkage;
  742. }
  743. IPSecFreeBuffer(&ntstatus, pESPBuffer);
  744. if (pHdrBuf) {
  745. IPSecFreeBuffer(&ntstatus, pHdrBuf);
  746. }
  747. if (pOptBuf) {
  748. IPSecFreeBuffer(&ntstatus, pOptBuf);
  749. }
  750. IPSecFreeBuffer(&ntstatus, pPadBuf);
  751. IPSecFreeBuffer(&ntstatus, pNewMdl);
  752. pContext->Flags = saveFlags;
  753. return status;
  754. }
  755. } else {
  756. IPSEC_GET_TOTAL_LEN(pESPBuffer, &hashBytes);
  757. }
  758. if (fCryptoOnly) {
  759. //
  760. // Zero out the hash.
  761. //
  762. IPSecZeroMemory(pPad + padLen, TruncatedLen);
  763. IPSecZeroMemory((PUCHAR)(pESP + 1) + pSA->sa_ReplayLen, pSA->sa_ivlen);
  764. }
  765. NdisBufferLength(pPadBuf) = padLen + TruncatedLen;
  766. pNdisPacket->Private.Tail = pPadBuf;
  767. }
  768. if (pSA->CONF_ALGO(Index) != IPSEC_ESP_NONE) {
  769. ADD_TO_LARGE_INTEGER(
  770. &pSA->sa_Stats.ConfidentialBytesSent,
  771. totalLen);
  772. ADD_TO_LARGE_INTEGER(
  773. &g_ipsec.Statistics.uConfidentialBytesSent,
  774. totalLen);
  775. }
  776. if (pSA->INT_ALGO(Index) != IPSEC_AH_NONE) {
  777. ADD_TO_LARGE_INTEGER(
  778. &pSA->sa_Stats.AuthenticatedBytesSent,
  779. hashBytes);
  780. ADD_TO_LARGE_INTEGER(
  781. &g_ipsec.Statistics.uAuthenticatedBytesSent,
  782. hashBytes);
  783. }
  784. //
  785. // Bump up the bytes transformed count.
  786. //
  787. ADD_TO_LARGE_INTEGER(
  788. &pSA->sa_TotalBytesTransformed,
  789. totalLen);
  790. //
  791. // Update the IP header length to reflect the Hughes header
  792. //
  793. switch (pSA->sa_EncapType) {
  794. case SA_UDP_ENCAP_TYPE_NONE:
  795. UpdateIPProtocol(pIPH, PROTOCOL_ESP);
  796. break;
  797. case SA_UDP_ENCAP_TYPE_IKE:
  798. UpdateIPProtocol(pIPH, 17);
  799. pNat=(NATENCAP UNALIGNED *)pTmpNat;
  800. memset(pNat,0,sizeof(NATENCAP));
  801. pNat->uh_src=pSA->sa_EncapContext.wSrcEncapPort;
  802. pNat->uh_dest=pSA->sa_EncapContext.wDesEncapPort;
  803. // UDP len = totalLen(original data len) + all new headers
  804. pNat->uh_length= NET_SHORT((USHORT)(totalLen + espLen + padLen + TruncatedLen));
  805. break;
  806. case SA_UDP_ENCAP_TYPE_OTHER:
  807. UpdateIPProtocol(pIPH, 17);
  808. pNatOther=(NATENCAP_OTHER UNALIGNED *)pTmpNat;
  809. memset(pNatOther,0,sizeof(NATENCAP_OTHER));
  810. pNatOther->uh_src=pSA->sa_EncapContext.wSrcEncapPort;
  811. pNatOther->uh_dest=pSA->sa_EncapContext.wDesEncapPort;
  812. // UDP len = totalLen(original data len) + all new headers
  813. pNatOther->uh_length= NET_SHORT((USHORT)(totalLen + espLen + padLen + TruncatedLen));
  814. break;
  815. }
  816. IPLength = NET_SHORT(pIPH->iph_length) + (USHORT)(espLen + padLen + TruncatedLen);
  817. if (fTunnel) {
  818. IPLength += sizeof(IPHeader);
  819. }
  820. UpdateIPLength(pIPH, NET_SHORT(IPLength));
  821. //
  822. // Return modified packet.
  823. //
  824. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Exiting IPSecCreateHughes, espLen: %lx, padLen: %lx, status: %lx", espLen, padLen, status));
  825. #if DBG
  826. IPSEC_DEBUG(LL_A, DBF_MDL, ("Exiting IPSecCreateHughes"));
  827. IPSEC_PRINT_CONTEXT(*ppSCContext);
  828. if (*ppNewData) {
  829. IPSEC_PRINT_MDL(*ppNewData);
  830. }
  831. else {
  832. IPSEC_PRINT_MDL(pData);
  833. }
  834. #endif
  835. return STATUS_SUCCESS;
  836. }
  837. NTSTATUS
  838. IPSecVerifyHughes(
  839. IN PUCHAR *pIPHeader,
  840. IN PVOID pData,
  841. IN PSA_TABLE_ENTRY pSA,
  842. IN ULONG Index,
  843. OUT PULONG pExtraBytes,
  844. IN BOOLEAN fCryptoDone,
  845. IN BOOLEAN fFastRcv
  846. )
  847. /*++
  848. Routine Description:
  849. Verify the combined esp-des-md5 transform, as outlined in
  850. draft-ietf-ipsec-esp-des-md5, on the send side.
  851. Arguments:
  852. pIPHeader - points to start of IP header.
  853. pData - points to the data after the IP header. IPRcvBuf*
  854. pSA - Sec. Assoc. entry
  855. pExtraBytes - out param to inform IP on recv path how many bytes IPSEC took off.
  856. Return Value:
  857. STATUS_SUCCESS
  858. Others:
  859. STATUS_INSUFFICIENT_RESOURCES
  860. STATUS_UNSUCCESSFUL (error in algo.)
  861. --*/
  862. {
  863. PESP pESP;
  864. NTSTATUS status = STATUS_SUCCESS;
  865. PNDIS_BUFFER pESPBuffer;
  866. PNDIS_BUFFER pPadBuffer;
  867. LONG espLen;
  868. UCHAR padLen;
  869. UCHAR payloadType;
  870. ULONG uTotalLen = 0;
  871. LONG totalLen;
  872. ULONG safetyLen;
  873. ULONG hdrLen;
  874. PUCHAR pHash;
  875. UCHAR tempHash[SAFETY_LEN+1];
  876. ULONG Len;
  877. UCHAR Buf[MAX_AH_OUTPUT_LEN];
  878. PUCHAR pAHData = Buf;
  879. PAUTH_ALGO pAlgo = &(auth_algorithms[pSA->INT_ALGO(Index)]);
  880. ULONG hashBytes = 0;
  881. IPRcvBuf *temp = (IPRcvBuf *)pData;
  882. IPHeader UNALIGNED *pIPH = (IPHeader UNALIGNED *)*pIPHeader;
  883. ULONG extraBytes = 0;
  884. USHORT FilterFlags;
  885. BOOLEAN fTunnel = ((pSA->sa_Flags & FLAGS_SA_TUNNEL) &&
  886. ((Index == 0) ||
  887. ((Index == 1) && (pSA->sa_Operation[0] == Compress))));
  888. ULONG TruncatedLen = (pSA->INT_ALGO(Index) != IPSEC_AH_NONE)? pSA->sa_TruncatedLen: 0;
  889. ULONG uPadLen = 0;
  890. IPRcvBuf * temp_pre = NULL;
  891. PUCHAR data;
  892. ULONG ExtraTransportNat=0;
  893. BOOLEAN bNatMdlChange=FALSE;
  894. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Entering IPSecVerifyHughes"));
  895. ASSERT(pSA->sa_Operation[Index] == Encrypt);
  896. hdrLen = (pIPH->iph_verlen & (UCHAR)~IP_VER_FLAG) << 2;
  897. //
  898. // Transport mode: payload is after IP header => payloadlen is total len - hdr len
  899. // Tunnel mode: payload starts at IP header => payloadlen is total len
  900. //
  901. IPSEC_GET_TOTAL_LEN_RCV_BUF(pData, &totalLen);
  902. switch(pSA->sa_EncapType) {
  903. case SA_UDP_ENCAP_TYPE_NONE:
  904. break;
  905. case SA_UDP_ENCAP_TYPE_IKE:
  906. ExtraTransportNat= sizeof(NATENCAP);
  907. break;
  908. case SA_UDP_ENCAP_TYPE_OTHER:
  909. ExtraTransportNat=sizeof(NATENCAP_OTHER);
  910. break;
  911. }
  912. //
  913. // Do we have enough in the buffer?
  914. //
  915. // BUG:566887 : Adding 8 bytes of minimum payload which have to be preent
  916. // The reason we have 8 bytes is because this function is specifically for
  917. // des-md5 and des has blocklen of 8 bytes
  918. Len = sizeof(ESP) + pSA->sa_ivlen + pSA->sa_ReplayLen + TruncatedLen +
  919. ExtraTransportNat +
  920. ((pSA->CONF_ALGO(Index) == IPSEC_ESP_NONE) ? 4: DES_BLOCKLEN);
  921. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("VerifyHughes: iph_len %d & hdrLen %d", NET_SHORT(pIPH->iph_length), hdrLen));
  922. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("VerifyHughes: DataLen %d & IPSecLen %d", totalLen, Len));
  923. if (totalLen < (LONG)Len || totalLen != (NET_SHORT(pIPH->iph_length) - hdrLen)) {
  924. ASSERT(FALSE);
  925. return STATUS_INVALID_PARAMETER;
  926. }
  927. //
  928. // See if the signature matches the hash
  929. // First get the *&*&* hash - its at the end of the packet...
  930. //
  931. //
  932. IPSecQueryRcvBuf((IPRcvBuf *)pData, &pESP, &espLen);
  933. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("VerifyHughes: First buffer %p", temp));
  934. //
  935. // Travel to the end of the packet and then backup TruncatedLen bytes
  936. //
  937. while (IPSEC_BUFFER_LINKAGE(temp)) {
  938. temp = IPSEC_BUFFER_LINKAGE(temp);
  939. }
  940. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("VerifyHughes: Last buffer %p", temp));
  941. //
  942. // See if we have at least the full hash and padding in this one. Else go thru'
  943. // the slow path.
  944. //
  945. IPSecQueryRcvBuf(temp, &pHash, &Len);
  946. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("VerifyHughes: Last buffer length %d", Len));
  947. safetyLen = MAX_PAD_LEN + TruncatedLen + 1;
  948. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("VerifyHughes: Safety length %d", safetyLen));
  949. if (Len >= safetyLen) {
  950. //
  951. // now read the hash out of the buffer
  952. //
  953. pHash = pHash + Len - TruncatedLen;
  954. //
  955. // also remove the hash from the buffer
  956. //
  957. IPSEC_ADJUST_BUFFER_LEN (temp, Len - TruncatedLen);
  958. extraBytes += TruncatedLen;
  959. Len -= TruncatedLen;
  960. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("VerifyHughes: Modified Last buffer length %d", Len));
  961. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("pHash: %p", pHash));
  962. } else {
  963. //
  964. // out of luck; need to grovel the lists for the TRUNC_LEN + MAX_PAD_LEN (SAFETY_LEN) bytes of data.
  965. // we copy out the last SAFETY_LEN bytes into another buffer and plug that into the list at the end
  966. // by re-allocing the last RcvBuf. We also zap the lengths of the remaining RcvBufs that contain these
  967. // special bytes.
  968. // NOTE: We also remove the hash from the buffer chain.
  969. //
  970. ULONG length;
  971. ULONG offset=0; // offset within the current buffer
  972. ULONG off=0; // offset in the dest buffer (tempHash)
  973. ULONG bytesLeft = safetyLen;
  974. IPRcvBuf tmpRcvBuf={0};
  975. LONG len = NET_SHORT(pIPH->iph_length) - safetyLen - hdrLen;
  976. temp = (IPRcvBuf *)pData;
  977. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("VerifyHughes: pData %p & Len %lx", pData, len));
  978. //
  979. // first travel to the buffer that points to a chain containing the
  980. // last SAFETY_LEN bytes by skipping (Total - SAFETY_LEN) bytes.
  981. //
  982. while (temp) {
  983. IPSecQueryRcvBuf(temp, &data, &length);
  984. len -= length;
  985. if (len < 0) {
  986. break;
  987. }
  988. temp = IPSEC_BUFFER_LINKAGE(temp);
  989. }
  990. if (!temp) {
  991. return STATUS_UNSUCCESSFUL;
  992. }
  993. //
  994. // pTemp now points to the last SAFETY_LEN bytes. Note that the last SAFETY_LEN bytes
  995. // might be in as many buffers and that there might be an offset in the current temp
  996. // where the last set of bytes starts.
  997. //
  998. len = -len;
  999. offset = length - len;
  1000. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("After skip temp: %p, Len: %d, offset: %d", temp, len, offset));
  1001. do {
  1002. RtlCopyMemory( tempHash+off,
  1003. data+offset,
  1004. len);
  1005. off += len;
  1006. bytesLeft -= len;
  1007. //
  1008. // Also remove the hash bytes from the chain as we traverse it.
  1009. //
  1010. IPSEC_ADJUST_BUFFER_LEN (temp, length - len);
  1011. if (bytesLeft == 0) {
  1012. ASSERT(off == safetyLen);
  1013. break;
  1014. }
  1015. temp = IPSEC_BUFFER_LINKAGE(temp);
  1016. if (!temp) {
  1017. return STATUS_UNSUCCESSFUL;
  1018. }
  1019. IPSecQueryRcvBuf(temp, &data, &length);
  1020. offset = 0;
  1021. len = length;
  1022. } while (TRUE);
  1023. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("After copy tempHash: %p", tempHash));
  1024. //
  1025. // Now we have an IPRcvBuf chain which has had SAFETY_LEN bytes removed.
  1026. // We reallocate these SAFETY_LEN bytes in the last buffer with help from IP.
  1027. //
  1028. tmpRcvBuf = *temp;
  1029. if (!TCPIP_ALLOC_BUFF(temp, safetyLen)) {
  1030. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Failed to realloc last 22 bytes"));
  1031. return STATUS_INSUFFICIENT_RESOURCES;
  1032. }
  1033. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Alloc'ed new temp: %p", temp));
  1034. //
  1035. // Now temp points to the new buffer with SAFETY_LEN number of bytes.
  1036. // Free the Original buffer.
  1037. //
  1038. TCPIP_FREE_BUFF(&tmpRcvBuf);
  1039. //
  1040. // Copy over the bytes into the buffer just allocated.
  1041. //
  1042. IPSEC_ADJUST_BUFFER_LEN (temp, safetyLen);
  1043. IPSecQueryRcvBuf(temp, &data, &Len);
  1044. ASSERT(Len == safetyLen);
  1045. RtlCopyMemory( data,
  1046. tempHash,
  1047. safetyLen);
  1048. //
  1049. // now read the hash out of the buffer
  1050. //
  1051. pHash = data + Len - TruncatedLen;
  1052. //
  1053. // also remove the hash from the buffer
  1054. //
  1055. IPSEC_ADJUST_BUFFER_LEN (temp, Len - TruncatedLen);
  1056. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Len in temp: %d", temp->ipr_size));
  1057. extraBytes += TruncatedLen;
  1058. Len -= TruncatedLen;
  1059. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("pHash: %p, Len: %d", pHash, Len));
  1060. }
  1061. //
  1062. // Hash is generated starting after the IPHeader, ie at start of pData
  1063. //
  1064. if (!fCryptoDone) {
  1065. status = IPSecHashMdlChainRecv( pSA,
  1066. (PVOID)pData, // source
  1067. pAHData, // dest
  1068. pSA->INT_ALGO(Index), // algo
  1069. &hashBytes,
  1070. Index,
  1071. ExtraTransportNat);
  1072. if (!NT_SUCCESS(status)) {
  1073. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Failed to hash, pData: %p", pData));
  1074. goto out;
  1075. }
  1076. if (!IPSecEqualMemory( pAHData,
  1077. pHash,
  1078. TruncatedLen * sizeof(UCHAR))) {
  1079. IPSecBufferEvent( pIPH->iph_src,
  1080. EVENT_IPSEC_AUTH_FAILURE,
  1081. 2,
  1082. TRUE);
  1083. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Failed to compare, pPyld: %p, pAHData: %p", pHash, pAHData));
  1084. IPSEC_INC_STATISTIC(dwNumPacketsNotAuthenticated);
  1085. status=IPSEC_INVALID_ESP;
  1086. goto out;
  1087. }
  1088. } else {
  1089. hashBytes = totalLen - TruncatedLen;
  1090. }
  1091. //
  1092. //BUG: 566887
  1093. //Requery the receive buf containing the ESP header
  1094. //In the process of removing the hash we may have removed
  1095. //some bytes from this buffer too
  1096. IPSecQueryRcvBuf((IPRcvBuf *)pData, &pESP, &espLen);
  1097. if (espLen < (LONG)(ExtraTransportNat + sizeof(ESP) + pSA->sa_ivlen + pSA->sa_ReplayLen)) {
  1098. // Slow path
  1099. BYTE Replay[4];
  1100. int i;
  1101. for (i=0;i<4;i++) {
  1102. IPSecGetRecvByteByOffset(pData,sizeof(ESP)+ExtraTransportNat+i,&Replay[i]);
  1103. }
  1104. status=IPSecChkReplayWindow(
  1105. NET_TO_HOST_LONG(*(ULONG UNALIGNED *)(Replay)),
  1106. pSA,
  1107. Index);
  1108. } else {
  1109. if (pSA->sa_EncapType != SA_UDP_ENCAP_TYPE_NONE) {
  1110. pESP = (PESP)(((UCHAR*)pESP) + ExtraTransportNat);
  1111. }
  1112. status=IPSecChkReplayWindow(
  1113. NET_TO_HOST_LONG(*(ULONG UNALIGNED *)(pESP + 1)),
  1114. pSA,
  1115. Index);
  1116. }
  1117. if (!NT_SUCCESS(status)) {
  1118. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Replay check failed, pSA: %p", pSA));
  1119. IPSEC_INC_STATISTIC(dwNumPacketsWithReplayDetection);
  1120. return status;
  1121. }
  1122. if (pSA->INT_ALGO(Index) != IPSEC_AH_NONE) {
  1123. ADD_TO_LARGE_INTEGER(
  1124. &pSA->sa_Stats.AuthenticatedBytesReceived,
  1125. hashBytes);
  1126. ADD_TO_LARGE_INTEGER(
  1127. &g_ipsec.Statistics.uAuthenticatedBytesReceived,
  1128. hashBytes);
  1129. }
  1130. espLen = sizeof(ESP) + pSA->sa_ivlen + pSA->sa_ReplayLen + ExtraTransportNat;
  1131. if ((pSA->CONF_ALGO(Index) != IPSEC_ESP_NONE) && !fCryptoDone) {
  1132. PCONFID_ALGO pConfAlgo;
  1133. ULONG blockLen;
  1134. pConfAlgo = &(conf_algorithms[pSA->CONF_ALGO(Index)]);
  1135. blockLen = pConfAlgo->blocklen;
  1136. //
  1137. // Make sure the data is aligned to 8 byte boundary.
  1138. //
  1139. if ((hashBytes - espLen) % blockLen) {
  1140. IPSEC_DEBUG(LL_A, DBF_ESP, ("ESP data not aligned: hashBytes %d, totalLen %d, espLen %d, blockLen %d", hashBytes, totalLen, espLen, blockLen));
  1141. return STATUS_UNSUCCESSFUL;
  1142. }
  1143. //
  1144. // Decrypt the entire block
  1145. //
  1146. status = IPSecDecryptBuffer(pData,
  1147. pSA,
  1148. &padLen,
  1149. &payloadType,
  1150. Index,
  1151. ExtraTransportNat);
  1152. if (!NT_SUCCESS(status)) {
  1153. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Failed the decrypt"));
  1154. goto out;
  1155. }
  1156. }
  1157. //
  1158. // Now remove the Pad too since it was not removed in Decrypt
  1159. //
  1160. padLen = *(pHash - (sizeof(UCHAR) << 1));
  1161. payloadType = *(pHash - sizeof(UCHAR));
  1162. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("ESP: PadLen: %d, PayloadType: %lx, pHash: %p, Len: %d", padLen, payloadType, pHash, Len));
  1163. //
  1164. // Entire pad may not be in this buffer.
  1165. //
  1166. uPadLen = padLen + NUM_EXTRA;
  1167. //
  1168. //BUG:566887
  1169. //Cant Receive a bogus padlen
  1170. //
  1171. if (totalLen-(LONG)(padLen +TruncatedLen+NUM_EXTRA) < (LONG)(sizeof(ESP) + pSA->sa_ivlen + pSA->sa_ReplayLen + ExtraTransportNat))
  1172. {
  1173. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Bogus Padlen\n"));
  1174. status=STATUS_INVALID_PARAMETER;
  1175. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Total size of all the buffers is smaller than the esp pad length"));
  1176. ASSERT(FALSE);
  1177. goto out;
  1178. }
  1179. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Total pad length = %d", uPadLen));
  1180. while (Len < uPadLen) {
  1181. IPSEC_ADJUST_BUFFER_LEN (temp, 0);
  1182. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Buffer: %p has a length %d - setting it to 0", temp, Len));
  1183. uPadLen -= Len;
  1184. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Net pad length = %d", uPadLen));
  1185. temp_pre = (IPRcvBuf *) pData;
  1186. while (temp_pre->ipr_next != temp) {
  1187. temp_pre = IPSEC_BUFFER_LINKAGE(temp_pre);
  1188. if (!temp_pre) {
  1189. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Total size of all the buffers is smaller than the esp pad length"));
  1190. ASSERT(temp_pre);
  1191. status= STATUS_UNSUCCESSFUL;
  1192. goto out;
  1193. }
  1194. }
  1195. IPSecQueryRcvBuf(temp_pre, &data, &Len);
  1196. temp = temp_pre;
  1197. }
  1198. IPSEC_ADJUST_BUFFER_LEN (temp, Len - uPadLen);
  1199. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Buffer: %p has a length %d - setting it to %d", temp, Len, Len - uPadLen));
  1200. extraBytes += (padLen + NUM_EXTRA);
  1201. if (pSA->CONF_ALGO(Index) != IPSEC_ESP_NONE) {
  1202. ADD_TO_LARGE_INTEGER(
  1203. &pSA->sa_Stats.ConfidentialBytesReceived,
  1204. totalLen - (extraBytes + espLen));
  1205. ADD_TO_LARGE_INTEGER(
  1206. &g_ipsec.Statistics.uConfidentialBytesReceived,
  1207. totalLen - (extraBytes + espLen));
  1208. }
  1209. //
  1210. // Bump up the bytes transformed count.
  1211. //
  1212. ADD_TO_LARGE_INTEGER(
  1213. &pSA->sa_TotalBytesTransformed,
  1214. totalLen);
  1215. if (!fTunnel) {
  1216. //
  1217. // Update the IP header length to reflect removal of the ESP header
  1218. //
  1219. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("VerifyHughes: iph_len %d, padLen %d, truncLen %d & espLen %d", NET_SHORT(pIPH->iph_length), uPadLen, TruncatedLen, espLen));
  1220. pIPH->iph_length =
  1221. NET_SHORT(
  1222. NET_SHORT(pIPH->iph_length) -
  1223. (USHORT)(espLen + uPadLen + TruncatedLen));
  1224. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("VerifyHughes: iph_len %d", NET_SHORT(pIPH->iph_length)));
  1225. //
  1226. // set the payload type in the IP header
  1227. //
  1228. pIPH->iph_protocol = payloadType;
  1229. //
  1230. // Remove the ESP header from the packet; pad was removed in Decrypt
  1231. //
  1232. IPSEC_SET_OFFSET_IN_BUFFER(pData, espLen);
  1233. //
  1234. // Move the IP header forward for filter/firewall hook, fast path only.
  1235. //
  1236. if (fFastRcv) {
  1237. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("VerifyHughes: fast receive true - "));
  1238. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Moving the IP header forward from %p by espLen %d", pIPH, espLen));
  1239. IPSecMoveMemory(((PUCHAR)pIPH) + espLen, (PUCHAR)pIPH, hdrLen);
  1240. *pIPHeader=(PUCHAR)pIPH+espLen;
  1241. pIPH = (IPHeader UNALIGNED *)*pIPHeader;
  1242. }
  1243. extraBytes += espLen;
  1244. //
  1245. // Return modified packet.
  1246. //
  1247. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("Exiting VerifyHughes: extra bytes %d & status: %lx", extraBytes, status));
  1248. *pExtraBytes += extraBytes;
  1249. #if DBG
  1250. IPSEC_GET_TOTAL_LEN_RCV_BUF(pData, &uTotalLen);
  1251. IPSEC_DEBUG(LL_A, DBF_HUGHES, ("VerifyHughes: iph_length %d & buflen %d", NET_SHORT(pIPH->iph_length), uTotalLen));
  1252. #endif
  1253. status= STATUS_SUCCESS;
  1254. goto out;
  1255. } else {
  1256. //
  1257. // set the payload type in the IP header
  1258. //
  1259. pIPH->iph_protocol = payloadType;
  1260. //
  1261. // Remove the ESP header from the packet
  1262. //
  1263. IPSEC_SET_OFFSET_IN_BUFFER(pData, espLen);
  1264. //
  1265. // Move the IP header forward for filter/firewall hook, fast path only.
  1266. //
  1267. if (fFastRcv) {
  1268. IPSecMoveMemory(((PUCHAR)pIPH) + espLen, (PUCHAR)pIPH, hdrLen);
  1269. *pIPHeader=(PUCHAR)pIPH+espLen;
  1270. pIPH = (IPHeader UNALIGNED *)*pIPHeader;
  1271. }
  1272. extraBytes += espLen;
  1273. //
  1274. // Return modified packet.
  1275. //
  1276. IPSEC_DEBUG(LL_A, DBF_ESP, ("Exiting IPSecVerifyHughes, espLen: %lx, status: %lx", espLen, status));
  1277. if (payloadType != IP_IN_IP) {
  1278. IPSEC_INC_STATISTIC(dwNumPacketsNotDecrypted);
  1279. IPSEC_DEBUG(LL_A, DBF_ESP, ("Bad payloadtype: %c", payloadType));
  1280. status = STATUS_INVALID_PARAMETER;
  1281. }
  1282. *pExtraBytes += extraBytes;
  1283. //
  1284. // Drop the original packet
  1285. //
  1286. // return status
  1287. }
  1288. out:
  1289. if (status == STATUS_SUCCESS &&
  1290. pSA->sa_EncapType != SA_UDP_ENCAP_TYPE_NONE) {
  1291. return IPSEC_SUCCESS_NAT_DECAPSULATE;
  1292. }
  1293. return status;
  1294. }
  1295. NTSTATUS
  1296. IPSecGetRecvByteByOffset(IPRcvBuf *pData,
  1297. LONG Offset,
  1298. BYTE *OutByte)
  1299. {
  1300. LONG TotalStartOffset=0; //Total start offset into data thus far
  1301. BYTE *pBuffer;
  1302. LONG CurBufLen;
  1303. while (pData) {
  1304. IPSecQueryRcvBuf(pData,&pBuffer,&CurBufLen);
  1305. if (Offset < CurBufLen+TotalStartOffset) {
  1306. *OutByte=pBuffer[Offset-TotalStartOffset];
  1307. return STATUS_SUCCESS;
  1308. }
  1309. TotalStartOffset +=CurBufLen;
  1310. pData=IPSEC_BUFFER_LINKAGE(pData);
  1311. }
  1312. return STATUS_UNSUCCESSFUL;
  1313. }
  1314. NTSTATUS
  1315. IPSecGetRecvBytesByOffset(IPRcvBuf *pData,
  1316. LONG Offset,
  1317. BYTE *pOutBuffer,
  1318. ULONG BufLen)
  1319. {
  1320. ULONG i;
  1321. NTSTATUS status;
  1322. for (i=0;i < BufLen; i++) {
  1323. status=IPSecGetRecvByteByOffset(pData,
  1324. Offset+i,
  1325. &pOutBuffer[i]);
  1326. if (!NT_SUCCESS(status)) {
  1327. return status;
  1328. }
  1329. }
  1330. return STATUS_SUCCESS;
  1331. }
  1332. NTSTATUS
  1333. IPSecSetRecvByteByOffset(IPRcvBuf *pData,
  1334. LONG Offset,
  1335. BYTE InByte)
  1336. {
  1337. LONG TotalStartOffset=0; //Total start offset into data thus far
  1338. BYTE *pBuffer;
  1339. LONG CurBufLen;
  1340. while (pData) {
  1341. IPSecQueryRcvBuf(pData,&pBuffer,&CurBufLen);
  1342. if (Offset < CurBufLen+TotalStartOffset) {
  1343. pBuffer[Offset-TotalStartOffset]=InByte;
  1344. return STATUS_SUCCESS;
  1345. }
  1346. TotalStartOffset +=CurBufLen;
  1347. pData=IPSEC_BUFFER_LINKAGE(pData);
  1348. }
  1349. return STATUS_UNSUCCESSFUL;
  1350. }