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.

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