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.

989 lines
28 KiB

  1. /*++
  2. Copyright (c) 1997-2001 Microsoft Corporation
  3. Module Name:
  4. ah.c
  5. Abstract:
  6. This module contains the code to create/verify Authentication 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. //
  16. // This array assumes one-to-one correspondence with the algoIds and
  17. // their order in ipsec.h.
  18. //
  19. #ifndef _TEST_PERF
  20. AUTH_ALGO auth_algorithms[] = {
  21. { ah_nullinit, ah_nullupdate, ah_nullfinish, MD5DIGESTLEN},
  22. { ah_hmacmd5init, ah_hmacmd5update, ah_hmacmd5finish, MD5DIGESTLEN},
  23. { ah_hmacshainit, ah_hmacshaupdate, ah_hmacshafinish, A_SHA_DIGEST_LEN},
  24. };
  25. #else
  26. AUTH_ALGO auth_algorithms[] = {
  27. { ah_nullinit, ah_nullupdate, ah_nullfinish, MD5DIGESTLEN},
  28. { ah_nullinit, ah_nullupdate, ah_nullfinish, MD5DIGESTLEN},
  29. { ah_nullinit, ah_nullupdate, ah_nullfinish, A_SHA_DIGEST_LEN},
  30. };
  31. #endif
  32. NTSTATUS
  33. IPSecCreateAH(
  34. IN PUCHAR pIPHeader,
  35. IN PVOID pData,
  36. IN PSA_TABLE_ENTRY pSA,
  37. IN ULONG Index,
  38. OUT PVOID *ppNewData,
  39. OUT PVOID *ppSCContext,
  40. OUT PULONG pExtraBytes,
  41. IN ULONG HdrSpace,
  42. IN BOOLEAN fSrcRoute,
  43. IN BOOLEAN fCryptoOnly
  44. )
  45. /*++
  46. Routine Description:
  47. Create the AH, given the packet. On the send side.
  48. Arguments:
  49. pIPHeader - points to start of IP header.
  50. pData - points to the data after the IP header. PNDIS_BUFFER
  51. pSA - Sec. Assoc. entry
  52. ppNewData - the new MDL chain to be used by TCPIP
  53. ppSCContext - send complete context used to clean up IPSEC headers
  54. pExtraBytes - the header expansion caused by this IPSEC header
  55. Return Value:
  56. STATUS_SUCCESS
  57. Others:
  58. STATUS_INSUFFICIENT_RESOURCES
  59. STATUS_UNSUCCESSFUL (error in algo.)
  60. --*/
  61. {
  62. NTSTATUS status = STATUS_SUCCESS;
  63. PNDIS_BUFFER pAHBuffer;
  64. PNDIS_BUFFER pHdrBuf = NULL;
  65. PNDIS_BUFFER pOptBuf = NULL;
  66. AH UNALIGNED *pAH;
  67. IPHeader UNALIGNED * pIPH;
  68. ULONG hdrLen;
  69. PIPSEC_SEND_COMPLETE_CONTEXT pContext;
  70. PAUTH_ALGO pAlgo;
  71. ULONG ahLen;
  72. ULONG ipNext;
  73. IPHeader UNALIGNED * pIPH2;
  74. UCHAR pAHData[MAX_AH_OUTPUT_LEN];
  75. ULONG totalBytes = 0;
  76. ULONG saveFlags = 0;
  77. ULONG Seq;
  78. USHORT IPLength;
  79. PNDIS_BUFFER pSaveDataLinkage = NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData);
  80. PNDIS_BUFFER pSaveOptLinkage = NULL;
  81. BOOLEAN fOuterAH = ((pSA->sa_Flags & FLAGS_SA_TUNNEL) &&
  82. (((Index == 1) && !pSA->COMP_ALGO(0)) || (Index == 2)));
  83. BOOLEAN fTunnel = ((pSA->sa_Flags & FLAGS_SA_TUNNEL) &&
  84. ((Index == 0) || ((Index == 1) && pSA->COMP_ALGO(0))));
  85. BOOLEAN fMuteDest = fSrcRoute && !fTunnel;
  86. IPSEC_DEBUG(AH, ("Entering IPSecCreateAH\n"));
  87. #if DBG
  88. IPSEC_DEBUG(MDL, ("Entering IPSecCreateAH\n"));
  89. IPSEC_PRINT_CONTEXT(*ppSCContext);
  90. IPSEC_PRINT_MDL(pData);
  91. #endif
  92. ASSERT(pSA->sa_Operation[Index] == Auth);
  93. if (pSA->INT_ALGO(Index) > NUM_AUTH_ALGOS) {
  94. return STATUS_INVALID_PARAMETER;
  95. }
  96. pAlgo = &(auth_algorithms[pSA->INT_ALGO(Index)]);
  97. ahLen = sizeof(AH) + pSA->sa_TruncatedLen * sizeof(UCHAR);
  98. //
  99. // If ESP was done previously, then dont alloc the context since we
  100. // can use the one alloced in ESP processing
  101. //
  102. if (*ppSCContext == NULL) {
  103. pContext = IPSecAllocateSendCompleteCtx(IPSEC_TAG_AH);
  104. if (!pContext) {
  105. IPSEC_DEBUG(AH, ("Failed to alloc. SendCtx\n"));
  106. return STATUS_INSUFFICIENT_RESOURCES;
  107. }
  108. IPSEC_INCREMENT(g_ipsec.NumSends);
  109. IPSecZeroMemory(pContext, sizeof(IPSEC_SEND_COMPLETE_CONTEXT));
  110. #if DBG
  111. RtlCopyMemory(pContext->Signature, "ISC1", 4);
  112. #endif
  113. *ppSCContext = pContext;
  114. } else {
  115. //
  116. // Piggybacking on ESP Context
  117. //
  118. pContext = *ppSCContext;
  119. saveFlags = pContext->Flags;
  120. }
  121. //
  122. // Get buffer for AH since no space reserved in the stack. Allocate enough for
  123. // the full hash, but hack the len to only truncated length.
  124. //
  125. IPSecAllocateBuffer(&status,
  126. &pAHBuffer,
  127. (PUCHAR *)&pAH,
  128. ahLen+(pAlgo->OutputLen - pSA->sa_TruncatedLen),
  129. IPSEC_TAG_AH);
  130. if (!NT_SUCCESS(status)) {
  131. IPSEC_DEBUG(AH, ("Failed to alloc. AH MDL\n"));
  132. pContext->Flags = saveFlags;
  133. return status;
  134. }
  135. NdisAdjustBufferLength(pAHBuffer, ahLen);
  136. pIPH = (IPHeader UNALIGNED *)pIPHeader;
  137. hdrLen = (pIPH->iph_verlen & (UCHAR)~IP_VER_FLAG) << 2;
  138. if (fTunnel) {
  139. PNDIS_BUFFER pSrcOptBuf;
  140. PUCHAR pOpt;
  141. PUCHAR pSrcOpt;
  142. ULONG optLen = 0;
  143. IPSEC_DEBUG(AH, ("AH Tunnel mode...\n"));
  144. //
  145. // Allocate an MDL for the new cleartext IP header
  146. //
  147. IPSecAllocateBuffer(&status,
  148. &pHdrBuf,
  149. (PUCHAR *)&pIPH2,
  150. sizeof(IPHeader),
  151. IPSEC_TAG_AH);
  152. if (!NT_SUCCESS(status)) {
  153. NTSTATUS ntstatus;
  154. IPSEC_DEBUG(AH, ("Failed to alloc. PAD MDL\n"));
  155. IPSecFreeBuffer(&ntstatus, pAHBuffer);
  156. pContext->Flags = saveFlags;
  157. return status;
  158. }
  159. *pExtraBytes += ahLen + sizeof(IPHeader);
  160. //
  161. // if we are going to fragment, and were tunneling, then, copy over the options, if present.
  162. // Also, use the original IP header on the outside and the new fabricated on the inside.
  163. // This is to make sure we free headers appropriately on the send completes.
  164. //
  165. //
  166. //
  167. // Now hookup the MDLs
  168. //
  169. pContext->Flags |= SCF_AH_TU;
  170. pContext->AHTuMdl = pAHBuffer;
  171. pContext->PrevTuMdl = (PNDIS_BUFFER)pData;
  172. pContext->OriTuMdl = NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData);
  173. NDIS_BUFFER_LINKAGE(pAHBuffer) = pHdrBuf;
  174. if (hdrLen > sizeof(IPHeader)) {
  175. if (HdrSpace < *pExtraBytes) {
  176. IPSEC_DEBUG(AH, ("Going to frag.\n"));
  177. pSrcOptBuf = NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData);
  178. pSaveOptLinkage = NDIS_BUFFER_LINKAGE(pSrcOptBuf);
  179. IPSecQueryNdisBuf(pSrcOptBuf, &pSrcOpt, &optLen);
  180. IPSecAllocateBuffer(&status,
  181. &pOptBuf,
  182. (PUCHAR *)&pOpt,
  183. hdrLen - sizeof(IPHeader),
  184. IPSEC_TAG_AH);
  185. if (!NT_SUCCESS(status)) {
  186. NTSTATUS ntstatus;
  187. IPSEC_DEBUG(AH, ("Failed to alloc. PAD MDL\n"));
  188. NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData) = pSaveDataLinkage;
  189. IPSecFreeBuffer(&ntstatus, pAHBuffer);
  190. IPSecFreeBuffer(&ntstatus, pHdrBuf);
  191. pContext->Flags = saveFlags;
  192. return status;
  193. }
  194. RtlCopyMemory(pOpt, pSrcOpt, hdrLen-sizeof(IPHeader));
  195. pContext->OptMdl = pOptBuf;
  196. IPSEC_DEBUG(AH, ("Copying options. S: %lx, D: %lx\n", pSrcOptBuf, pOptBuf));
  197. //
  198. // replace the original Opt Mdl with ours.
  199. //
  200. NDIS_BUFFER_LINKAGE(pOptBuf) = NDIS_BUFFER_LINKAGE(pSrcOptBuf);
  201. NDIS_BUFFER_LINKAGE(pHdrBuf) = pOptBuf;
  202. IPSEC_DEBUG(AH, ("Options; pointed Hdrbuf: %lx to pOptBuf: %lx\n", pHdrBuf, pOptBuf));
  203. *pExtraBytes += hdrLen-sizeof(IPHeader);
  204. } else {
  205. IPSEC_DEBUG(AH, ("Options; pointed Hdrbuf: %lx to link(pData): %lx\n", pHdrBuf, NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData)));
  206. NDIS_BUFFER_LINKAGE(pHdrBuf) = NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData);
  207. }
  208. } else {
  209. IPSEC_DEBUG(AH, ("No options; pointed Hdrbuf: %lx to link(pData): %lx\n", pHdrBuf, NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData)));
  210. NDIS_BUFFER_LINKAGE(pHdrBuf) = NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData);
  211. }
  212. NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData) = pAHBuffer;
  213. //
  214. // xsum the new IP header since we expect that to be the case
  215. // at this stage in tpt mode.
  216. //
  217. RtlCopyMemory(pIPH2, pIPH, sizeof(IPHeader));
  218. //
  219. // no options in the outer header; reset the len.
  220. //
  221. pIPH->iph_verlen = IP_VERSION + (sizeof(IPHeader) >> 2);
  222. //
  223. // also reset the frag. params.
  224. //
  225. pIPH->iph_offset &= ~(IP_MF_FLAG | IP_OFFSET_MASK);
  226. ASSERT(pSA->sa_TunnelAddr);
  227. //
  228. // Tunnel starts here; replace dest addr to point to Tunnel end if specified
  229. // else tunnel ends at final dest
  230. //
  231. pIPH->iph_dest = pSA->sa_TunnelAddr;
  232. //
  233. // The first pended packet on a gateway (proxy negotiating for two subnets)
  234. // would come via the transmit path. Hence the source address would not be
  235. // kosher. We need to replace the src address in that case also.
  236. // We get this from the corresponding inbound SA's tunnel addr.
  237. //
  238. pIPH->iph_src = pSA->sa_SrcTunnelAddr;
  239. pIPH->iph_id = (ushort) TCPIP_GEN_IPID();
  240. pIPH->iph_xsum = 0;
  241. pIPH->iph_xsum = ~xsum(pIPH, sizeof(IPHeader));
  242. //
  243. // Set up headers so CreateHash works as in Tpt mode.
  244. //
  245. pIPHeader = (PUCHAR)pIPH;
  246. *ppNewData = (PVOID)pData;
  247. ipNext = ((UNALIGNED IPHeader *)pIPHeader)->iph_protocol;
  248. pAH->ah_next = (UCHAR)IP_IN_IP;
  249. } else {
  250. *pExtraBytes += ahLen;
  251. if (hdrLen > sizeof(IPHeader)) {
  252. //
  253. // Options present - chain AH after options
  254. //
  255. if (fOuterAH) {
  256. pContext->Flags |= SCF_AH_2;
  257. pContext->OriAHMdl2 = NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData));
  258. pContext->PrevAHMdl2 = NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData);
  259. pAHBuffer->Next = pContext->OriAHMdl2;
  260. } else {
  261. pContext->Flags |= SCF_AH;
  262. pContext->OriAHMdl = NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData));
  263. pContext->PrevMdl = NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData);
  264. pAHBuffer->Next = pContext->OriAHMdl;
  265. }
  266. NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData)) = pAHBuffer;
  267. } else {
  268. //
  269. // Chain the AH buffer after IP header
  270. //
  271. if (fOuterAH) {
  272. pContext->Flags |= SCF_AH_2;
  273. pContext->OriAHMdl2 = NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData);
  274. pContext->PrevAHMdl2 = (PNDIS_BUFFER)pData;
  275. pAHBuffer->Next = pContext->OriAHMdl2;
  276. } else {
  277. pContext->Flags |= SCF_AH;
  278. pContext->OriAHMdl = NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData);
  279. pContext->PrevMdl = (PNDIS_BUFFER)pData;
  280. pAHBuffer->Next = pContext->OriAHMdl;
  281. }
  282. NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData) = pAHBuffer;
  283. }
  284. if (fOuterAH) {
  285. pContext->AHMdl2 = pAHBuffer;
  286. } else {
  287. pContext->AHMdl = pAHBuffer;
  288. }
  289. pAH->ah_next = ((UNALIGNED IPHeader *)pIPHeader)->iph_protocol;
  290. }
  291. //
  292. // Initialize the other fields of the AH header
  293. //
  294. pAH->ah_len = (UCHAR)((pSA->sa_TruncatedLen + pSA->sa_ReplayLen) >> 2);
  295. pAH->ah_reserved = 0;
  296. pAH->ah_spi = HOST_TO_NET_LONG(pSA->sa_OtherSPIs[Index]);
  297. Seq = IPSEC_INCREMENT(pSA->sa_ReplaySendSeq[Index]);
  298. pAH->ah_replay = HOST_TO_NET_LONG(Seq);
  299. //
  300. // Update the IP total length to reflect the AH header
  301. //
  302. IPLength = NET_SHORT(pIPH->iph_length) + (USHORT)ahLen;
  303. if (fTunnel) {
  304. IPLength += sizeof(IPHeader);
  305. }
  306. UpdateIPLength(pIPH, NET_SHORT(IPLength));
  307. UpdateIPProtocol(pIPH, PROTOCOL_AH);
  308. ADD_TO_LARGE_INTEGER(
  309. &pSA->sa_Stats.AuthenticatedBytesSent,
  310. NET_SHORT(pIPH->iph_length));
  311. ADD_TO_LARGE_INTEGER(
  312. &g_ipsec.Statistics.uAuthenticatedBytesSent,
  313. NET_SHORT(pIPH->iph_length));
  314. //
  315. // Generate the Hash.
  316. //
  317. if (!fCryptoOnly) {
  318. status = IPSecGenerateHash( pIPHeader,
  319. (PVOID)pData,
  320. pSA,
  321. (PUCHAR)(pAH + 1),
  322. fMuteDest,
  323. FALSE, // not on recv path
  324. pAlgo,
  325. Index);
  326. if (!NT_SUCCESS(status)) {
  327. NTSTATUS ntstatus;
  328. IPSEC_DEBUG(AH, ("Failed to hash, pAH: %lx\n", pAH));
  329. NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData) = pSaveDataLinkage;
  330. if (pSaveOptLinkage) {
  331. NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE((PNDIS_BUFFER)pData)) = pSaveOptLinkage;
  332. }
  333. IPSecFreeBuffer(&ntstatus, pAHBuffer);
  334. if (pHdrBuf) {
  335. IPSecFreeBuffer(&ntstatus, pHdrBuf);
  336. }
  337. if (pOptBuf) {
  338. IPSecFreeBuffer(&ntstatus, pOptBuf);
  339. }
  340. pContext->Flags = saveFlags;
  341. *ppNewData = NULL;
  342. return status;
  343. }
  344. } else {
  345. //
  346. // Zero out the hash.
  347. //
  348. IPSecZeroMemory((PUCHAR)(pAH + 1), pSA->sa_TruncatedLen);
  349. }
  350. //
  351. // Bump up the bytes transformed count.
  352. //
  353. ADD_TO_LARGE_INTEGER(
  354. &pSA->sa_TotalBytesTransformed,
  355. NET_SHORT(pIPH->iph_length));
  356. //
  357. // Return modified packet.
  358. //
  359. IPSEC_DEBUG(AH, ("Exiting IPSecCreateAH, ahLen: %lx, status: %lx\n", ahLen, status));
  360. #if DBG
  361. IPSEC_DEBUG(MDL, ("Exiting IPSecCreateAH\n"));
  362. IPSEC_PRINT_CONTEXT(*ppSCContext);
  363. if (*ppNewData) {
  364. IPSEC_PRINT_MDL(*ppNewData);
  365. }
  366. else {
  367. IPSEC_PRINT_MDL(pData);
  368. }
  369. #endif
  370. return STATUS_SUCCESS;
  371. }
  372. NTSTATUS
  373. IPSecVerifyAH(
  374. IN PUCHAR *pIPHeader,
  375. IN PVOID pData,
  376. IN PSA_TABLE_ENTRY pSA,
  377. IN ULONG Index,
  378. OUT PULONG pExtraBytes,
  379. IN BOOLEAN fSrcRoute,
  380. IN BOOLEAN fCryptoDone,
  381. IN BOOLEAN fFastRcv
  382. )
  383. /*++
  384. Routine Description:
  385. Verify the AH, given the packet. If AH kosher, strips off the AH from
  386. pData.
  387. Arguments:
  388. pIPHeader - points to start of IP header.
  389. pData - points to the data after the IP header.
  390. pSA - Sec. Assoc. entry
  391. pExtraBytes - out param to inform IP on recv path how many bytes IPSEC took off.
  392. Return Value:
  393. STATUS_SUCCESS
  394. Others:
  395. STATUS_UNSUCCESSFUL (packet not kosher - bad AH)
  396. STATUS_INSUFFICIENT_RESOURCES
  397. --*/
  398. {
  399. NTSTATUS status = STATUS_SUCCESS;
  400. PUCHAR pPyld;
  401. ULONG Len;
  402. LONG ahLen;
  403. LONG totalLen;
  404. UCHAR Buf[MAX_AH_OUTPUT_LEN];
  405. PUCHAR pAHData = Buf;
  406. IPHeader UNALIGNED *pIPH = (IPHeader UNALIGNED *)*pIPHeader;
  407. ULONG extraBytes = 0;
  408. ULONG hdrLen;
  409. PAUTH_ALGO pAlgo;
  410. USHORT FilterFlags;
  411. BOOLEAN fTunnel = ((pSA->sa_Flags & FLAGS_SA_TUNNEL) &&
  412. ((Index == 0) ||
  413. ((Index == 1) && (pSA->sa_Operation[0] == Compress))));
  414. IPSEC_DEBUG(AH, ("Entering IPSecVerifyAH\n"));
  415. ASSERT(pSA->sa_Operation[Index] == Auth);
  416. if (pSA->INT_ALGO(Index) > NUM_AUTH_ALGOS) {
  417. return STATUS_INVALID_PARAMETER;
  418. }
  419. hdrLen = (pIPH->iph_verlen & (UCHAR)~IP_VER_FLAG) << 2;
  420. pAlgo = &(auth_algorithms[pSA->INT_ALGO(Index)]);
  421. ahLen = sizeof(AH) + pSA->sa_TruncatedLen * sizeof(UCHAR);
  422. IPSEC_GET_TOTAL_LEN_RCV_BUF(pData, &totalLen);
  423. //
  424. // Do we have enough in the buffer?
  425. //
  426. if (totalLen < ahLen) {
  427. return STATUS_INVALID_PARAMETER;
  428. }
  429. //
  430. // Compare the hash with the AH from packet
  431. // First buffer has the AH
  432. //
  433. IPSecQueryRcvBuf(pData, &pPyld, &Len);
  434. //
  435. // Size OK?
  436. //
  437. if (((UNALIGNED AH *)pPyld)->ah_len !=
  438. (UCHAR)((pSA->sa_TruncatedLen + pSA->sa_ReplayLen) >> 2)) {
  439. IPSEC_DEBUG(AH, ("Failed size check: in: %x, need: %x\n",
  440. ((UNALIGNED AH *)pPyld)->ah_len,
  441. (UCHAR)((pSA->sa_TruncatedLen + pSA->sa_ReplayLen) >> 2)));
  442. return STATUS_INVALID_PARAMETER;
  443. }
  444. //
  445. // Generate the Hash
  446. //
  447. if (!fCryptoDone) {
  448. status = IPSecGenerateHash( *pIPHeader,
  449. pData,
  450. pSA,
  451. pAHData,
  452. fSrcRoute,
  453. TRUE,
  454. pAlgo,
  455. Index); // on recv path
  456. if (!NT_SUCCESS(status)) {
  457. IPSEC_DEBUG(AH, ("Failed to hash, pData: %lx\n", pData));
  458. return status;
  459. }
  460. if (!IPSecEqualMemory( pAHData,
  461. pPyld + sizeof(AH),
  462. pSA->sa_TruncatedLen)) {
  463. IPSecBufferEvent( pIPH->iph_src,
  464. EVENT_IPSEC_AUTH_FAILURE,
  465. 1,
  466. TRUE);
  467. IPSEC_DEBUG(AH, ("Failed to compare, pPyld: %lx, pAHData: %lx\n", pPyld, pAHData));
  468. IPSEC_DEBUG(GENHASH, ("AHData: %lx-%lx-%lx\n",
  469. *(ULONG *)&(pAHData)[0],
  470. *(ULONG *)&(pAHData)[4],
  471. *(ULONG *)&(pAHData)[8]));
  472. IPSEC_DEBUG(GENHASH, ("PyldHash: %lx-%lx-%lx\n",
  473. *(ULONG *)&((UCHAR *)(pPyld + sizeof(AH)))[0],
  474. *(ULONG *)&((UCHAR *)(pPyld + sizeof(AH)))[4],
  475. *(ULONG *)&((UCHAR *)(pPyld + sizeof(AH)))[8]));
  476. IPSEC_INC_STATISTIC(dwNumPacketsNotAuthenticated);
  477. return IPSEC_INVALID_AH;
  478. }
  479. }
  480. ADD_TO_LARGE_INTEGER(
  481. &pSA->sa_Stats.AuthenticatedBytesReceived,
  482. NET_SHORT(pIPH->iph_length));
  483. ADD_TO_LARGE_INTEGER(
  484. &g_ipsec.Statistics.uAuthenticatedBytesReceived,
  485. NET_SHORT(pIPH->iph_length));
  486. //
  487. // Check the replay window
  488. //
  489. status=IPSecChkReplayWindow(
  490. NET_TO_HOST_LONG(((UNALIGNED AH *)pPyld)->ah_replay),
  491. pSA,
  492. Index);
  493. if (!NT_SUCCESS(status)) {
  494. IPSEC_DEBUG(AH, ("Replay check failed, pPyld: %lx, pAHData: %lx\n", pPyld, pAHData));
  495. IPSEC_INC_STATISTIC(dwNumPacketsWithReplayDetection);
  496. return status;
  497. }
  498. IPSEC_DEBUG(AH, ("IP Len: %lx\n", pIPH->iph_length));
  499. pIPH->iph_length = NET_SHORT(NET_SHORT(pIPH->iph_length) - (USHORT)ahLen);
  500. IPSEC_DEBUG(AH, ("IP Len: %lx\n", pIPH->iph_length));
  501. //
  502. // Restore the protocol from AH header
  503. //
  504. pIPH->iph_protocol = ((UNALIGNED AH *)pPyld)->ah_next;
  505. IPSEC_DEBUG(AH, ("Matched!! Restored protocol %x\n", pIPH->iph_protocol));
  506. //
  507. // Remove the AH from the packet
  508. //
  509. IPSEC_SET_OFFSET_IN_BUFFER(pData, ahLen);
  510. //
  511. // Move the IP header forward for filter/firewall hook, fast path only.
  512. //
  513. if (fFastRcv) {
  514. IPSecMoveMemory(((PUCHAR)pIPH) + ahLen, (PUCHAR)pIPH, hdrLen);
  515. *pIPHeader=(PUCHAR)pIPH+ahLen;
  516. pIPH = (IPHeader UNALIGNED *)*pIPHeader;
  517. }
  518. extraBytes += ahLen;
  519. //
  520. // Bump up the bytes transformed count.
  521. //
  522. ADD_TO_LARGE_INTEGER(
  523. &pSA->sa_TotalBytesTransformed,
  524. NET_SHORT(pIPH->iph_length));
  525. if (fTunnel) {
  526. if (pIPH->iph_protocol != IP_IN_IP) {
  527. IPSEC_DEBUG(AH, ("BAD protocol in IP: %x\n", pIPH->iph_protocol));
  528. return STATUS_INVALID_PARAMETER;
  529. }
  530. }
  531. *pExtraBytes += extraBytes;
  532. IPSEC_DEBUG(AH, ("Exiting IPSecVerifyAH\n"));
  533. return status;
  534. }
  535. NTSTATUS
  536. IPSecGenerateHash(
  537. IN PUCHAR pIPHeader,
  538. IN PVOID pData,
  539. IN PSA_TABLE_ENTRY pSA,
  540. IN PUCHAR pAHData,
  541. IN BOOLEAN fMuteDest,
  542. IN BOOLEAN fIncoming,
  543. IN PAUTH_ALGO pAlgo,
  544. IN ULONG Index
  545. )
  546. /*++
  547. Routine Description:
  548. Arguments:
  549. pIPHeader - points to start of IP header.
  550. pData - points to the entire IP datagram, starting at the IP Header
  551. pSA - Sec. Assoc. entry
  552. pAHData - buffer to contain the generated hash
  553. fIncoming - TRUE if on recv path.
  554. pAlgo - the auth_algo being used
  555. Return Value:
  556. STATUS_SUCCESS
  557. Others:
  558. STATUS_UNSUCCESSFUL (packet not kosher - bad AH)
  559. STATUS_INSUFFICIENT_RESOURCES
  560. --*/
  561. {
  562. ULONG numBytesPayload;
  563. ULONG i;
  564. PUCHAR pPayload;
  565. IPHeader UNALIGNED *pIPH = (UNALIGNED IPHeader *)pIPHeader;
  566. PUCHAR pOptions;
  567. PNDIS_BUFFER pBuf = (PNDIS_BUFFER)pData;
  568. ULONG hdrLen;
  569. ULONG ahLen;
  570. NTSTATUS status;
  571. ALGO_STATE State = {0};
  572. BOOLEAN fTunnel = ( (pSA->sa_Flags & FLAGS_SA_TUNNEL) &&
  573. ((Index == 0) ||
  574. ((Index == 1) && (pSA->sa_Operation[0] == Compress))));
  575. //
  576. // These are saved since they can change enroute
  577. //
  578. //
  579. // Scratch array used for AH calculation
  580. //
  581. UCHAR zero[MAX_IP_OPTION_SIZE];
  582. UCHAR savetos; // Type of service.
  583. USHORT saveoffset; // Flags and fragment offset.
  584. UCHAR savettl; // Time to live.
  585. USHORT savexsum; // Header checksum.
  586. IPAddr savedest; // Dest address.
  587. IPSEC_DEBUG(AH, ("Entering IPSecGenerateHash\n"));
  588. ahLen = sizeof(AH) + pSA->sa_TruncatedLen * sizeof(UCHAR);
  589. State.as_sa = pSA;
  590. IPSecZeroMemory(zero, sizeof(zero));
  591. status = pAlgo->init(&State, Index);
  592. if (!NT_SUCCESS(status)) {
  593. IPSEC_DEBUG(AH, ("init failed: %lx\n", status));
  594. }
  595. //
  596. // Save, then zero out fields that can change enroute
  597. //
  598. savetos = pIPH->iph_tos;
  599. saveoffset = pIPH->iph_offset;
  600. savettl = pIPH->iph_ttl;
  601. savexsum = pIPH->iph_xsum;
  602. pIPH->iph_tos = 0;
  603. pIPH->iph_offset = 0;
  604. pIPH->iph_ttl = 0;
  605. pIPH->iph_xsum = 0;
  606. //
  607. // Mute dest address as well if source routing
  608. //
  609. if (fMuteDest) {
  610. savedest = pIPH->iph_dest;
  611. pIPH->iph_dest = 0;
  612. }
  613. //
  614. // Call MD5 to create the header hash
  615. //
  616. pAlgo->update(&State, pIPHeader, sizeof(IPHeader));
  617. #if DBG
  618. if (fIncoming) {
  619. IPSEC_DEBUG(GENHASH, ("IPHeader to Hash: %lx-%lx-%lx-%lx-%lx\n",
  620. *(ULONG *)&(pIPHeader)[0],
  621. *(ULONG *)&(pIPHeader)[4],
  622. *(ULONG *)&(pIPHeader)[8],
  623. *(ULONG *)&(pIPHeader)[12],
  624. *(ULONG *)&(pIPHeader)[16]));
  625. }
  626. #endif
  627. //
  628. // Restore the zeroed fields
  629. //
  630. pIPH->iph_tos = savetos;
  631. pIPH->iph_offset = saveoffset;
  632. pIPH->iph_ttl = savettl;
  633. pIPH->iph_xsum = savexsum;
  634. //
  635. // Restore dest address as well for source routing
  636. //
  637. if (fMuteDest) {
  638. pIPH->iph_dest = savedest;
  639. }
  640. //
  641. // Now, do the options if they exist
  642. //
  643. hdrLen = (pIPH->iph_verlen & (UCHAR)~IP_VER_FLAG) << 2;
  644. if (hdrLen > sizeof(IPHeader)) {
  645. UCHAR cLength;
  646. ULONG uIndex = 0;
  647. ULONG uOptLen = hdrLen - sizeof(IPHeader);
  648. ASSERT(!fTunnel);
  649. if (fIncoming) {
  650. pOptions = (PUCHAR)(pIPH + 1);
  651. } else {
  652. //
  653. // Options are in second MDL... on send side
  654. //
  655. pBuf = NDIS_BUFFER_LINKAGE(pBuf);
  656. IPSecQueryNdisBuf(pBuf, &pOptions, &uOptLen);
  657. }
  658. IPSEC_DEBUG(AH, ("Got options: %lx\n", pOptions));
  659. //
  660. // Some options may need to be zeroed out...
  661. //
  662. while (uIndex < uOptLen) {
  663. switch (*pOptions) {
  664. case IP_OPT_EOL:
  665. pAlgo->update(&State, zero, 1);
  666. uIndex = uOptLen;
  667. break;
  668. //
  669. // Zeroed for AH calculation
  670. //
  671. case IP_OPT_NOP:
  672. pAlgo->update(&State, zero, 1);
  673. uIndex++;
  674. pOptions++;
  675. break;
  676. case IP_OPT_LSRR:
  677. case IP_OPT_SSRR:
  678. case IP_OPT_RR:
  679. case IP_OPT_TS:
  680. cLength = pOptions[IP_OPT_LENGTH];
  681. pAlgo->update(&State, zero, cLength);
  682. uIndex += cLength;
  683. pOptions += cLength;
  684. break;
  685. //
  686. // Assumed invariant; used for AH calc
  687. //
  688. case IP_OPT_ROUTER_ALERT:
  689. case IP_OPT_SECURITY:
  690. default:
  691. cLength = pOptions[IP_OPT_LENGTH];
  692. pAlgo->update(&State, pOptions, cLength);
  693. uIndex += cLength;
  694. pOptions += cLength;
  695. break;
  696. }
  697. }
  698. }
  699. //
  700. // Go over the remaining payload, creating the hash
  701. //
  702. // NOTE: We differentiate between the send and recv since the
  703. // buffer formats are different
  704. //
  705. if (fIncoming) {
  706. IPRcvBuf *pBuf = (IPRcvBuf *)pData;
  707. ULONG Len;
  708. LONG remainLen;
  709. UCHAR UNALIGNED *pPyld;
  710. //
  711. // First buffer shd be the AH itself
  712. //
  713. IPSecQueryRcvBuf(pBuf, &pPyld, &Len);
  714. //
  715. // Do the first portion of the header.
  716. //
  717. pAlgo->update(&State, pPyld, sizeof(AH));
  718. #if DBG
  719. if (fIncoming) {
  720. IPSEC_DEBUG(GENHASH, ("AHHeader to Hash: %lx-%lx-%lx\n",
  721. *(ULONG *)&(pPyld)[0],
  722. *(ULONG *)&(pPyld)[4],
  723. *(ULONG *)&(pPyld)[8]));
  724. }
  725. #endif
  726. //
  727. // The authentication data should be considered as 0.
  728. // In our case, the data length is fixed at pSA->sa_TruncatedLen bytes
  729. //
  730. pAlgo->update(&State, zero, pSA->sa_TruncatedLen);
  731. //
  732. // Jump over the remaining AH: need to take care of situations
  733. // where ICV is chained (Raid 146275).
  734. //
  735. if (((LONG)Len - (LONG)ahLen) >= 0) {
  736. pPyld += ahLen;
  737. IPSEC_DEBUG(AH, ("Jumped over IPSEC res: %lx, len: %lx\n", pPyld, Len));
  738. //
  739. // Tpt header is right after AH
  740. //
  741. pAlgo->update(&State, pPyld, Len - ahLen);
  742. } else {
  743. //
  744. // Need to jump over ICV if it expands over multiple buffers
  745. //
  746. remainLen = pSA->sa_TruncatedLen - (Len - sizeof(AH));
  747. IPSEC_DEBUG(AH, ("Jumped over IPSEC res: %lx, remainlen: %lx\n", pPyld, remainLen));
  748. while (remainLen > 0 && (pBuf = IPSEC_BUFFER_LINKAGE(pBuf))) {
  749. IPSecQueryRcvBuf(pBuf, &pPyld, &Len);
  750. remainLen -= Len;
  751. }
  752. //
  753. // Do the possible partial data after AH
  754. //
  755. if (remainLen < 0 && pBuf) {
  756. pPyld += Len + remainLen;
  757. pAlgo->update(&State, pPyld, -remainLen);
  758. }
  759. }
  760. //
  761. // Now do the remaining chain
  762. //
  763. while (pBuf = IPSEC_BUFFER_LINKAGE(pBuf)) {
  764. IPSecQueryRcvBuf(pBuf, &pPyld, &Len);
  765. pAlgo->update(&State, pPyld, Len);
  766. }
  767. } else {
  768. UCHAR UNALIGNED *pPyld;
  769. ULONG Len;
  770. //
  771. // Second (or third if options present) buffer shd be the AH itself
  772. //
  773. pBuf = NDIS_BUFFER_LINKAGE(pBuf);
  774. IPSecQueryNdisBuf(pBuf, &pPyld, &Len);
  775. //
  776. // Do the first portion of the header.
  777. //
  778. pAlgo->update(&State, pPyld, sizeof(AH));
  779. //
  780. // The authentication data should be considered as 0.
  781. // In our case, the data length is fixed at pSA->sa_TruncatedLen bytes
  782. //
  783. pAlgo->update(&State, zero, pSA->sa_TruncatedLen);
  784. //
  785. // Skip over the remaining AH section
  786. //
  787. pPyld += ahLen;
  788. IPSEC_DEBUG(AH, ("Jumped over IPSEC Len: %lx, hdrlen: %lx\n", Len, hdrLen));
  789. pAlgo->update(&State, pPyld, Len - ahLen);
  790. //
  791. // Now do the remaining chain
  792. //
  793. while (pBuf = NDIS_BUFFER_LINKAGE(pBuf)) {
  794. IPSecQueryNdisBuf(pBuf, &pPyld, &Len);
  795. pAlgo->update(&State, pPyld, Len);
  796. }
  797. }
  798. pAlgo->finish(&State, pAHData, Index);
  799. //
  800. // Copy out the hash - get the truncated hash out, then zero out the rest
  801. //
  802. TRUNCATE(pAHData, pAHData, pSA->sa_TruncatedLen, MD5DIGESTLEN);
  803. IPSEC_DEBUG(AH, ("Exiting IPSecGenerateMD5\n"));
  804. return STATUS_SUCCESS;
  805. }