1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.ipsec.ike.cts; 17 18 import static android.ipsec.ike.cts.PacketUtils.BytePayload; 19 import static android.ipsec.ike.cts.PacketUtils.IP4_HDRLEN; 20 import static android.ipsec.ike.cts.PacketUtils.IP6_HDRLEN; 21 import static android.ipsec.ike.cts.PacketUtils.Ip4Header; 22 import static android.ipsec.ike.cts.PacketUtils.Ip6Header; 23 import static android.ipsec.ike.cts.PacketUtils.IpHeader; 24 import static android.ipsec.ike.cts.PacketUtils.Payload; 25 import static android.ipsec.ike.cts.PacketUtils.UDP_HDRLEN; 26 import static android.ipsec.ike.cts.PacketUtils.UdpHeader; 27 import static android.system.OsConstants.IPPROTO_UDP; 28 29 import static com.android.internal.util.HexDump.hexStringToByteArray; 30 31 import static org.junit.Assert.fail; 32 33 import android.os.ParcelFileDescriptor; 34 35 import java.net.Inet4Address; 36 import java.net.Inet6Address; 37 import java.net.InetAddress; 38 import java.nio.ByteBuffer; 39 import java.util.ArrayList; 40 import java.util.Arrays; 41 import java.util.List; 42 import java.util.function.Predicate; 43 44 public class IkeTunUtils extends TunUtils { 45 private static final int PORT_LEN = 2; 46 47 private static final int NON_ESP_MARKER_LEN = 4; 48 private static final byte[] NON_ESP_MARKER = new byte[NON_ESP_MARKER_LEN]; 49 50 private static final int IKE_INIT_SPI_OFFSET = 0; 51 private static final int IKE_FIRST_PAYLOAD_OFFSET = 16; 52 private static final int IKE_IS_RESP_BYTE_OFFSET = 19; 53 private static final int IKE_MSG_ID_OFFSET = 20; 54 private static final int IKE_HEADER_LEN = 28; 55 private static final int IKE_FRAG_NUM_OFFSET = 32; 56 private static final int IKE_PAYLOAD_TYPE_SKF = 53; 57 58 private static final int RSP_FLAG_MASK = 0x20; 59 IkeTunUtils(ParcelFileDescriptor tunFd)60 public IkeTunUtils(ParcelFileDescriptor tunFd) { 61 super(tunFd); 62 } 63 64 /** 65 * Await the expected IKE request inject an IKE response (or a list of response fragments) 66 * 67 * @param ikeRespDataFragmentsHex IKE response hex (or a list of response fragments) without 68 * IP/UDP headers or NON ESP MARKER. 69 */ awaitReqAndInjectResp( long expectedInitIkeSpi, int expectedMsgId, boolean expectedUseEncap, String... ikeRespDataFragmentsHex)70 public byte[] awaitReqAndInjectResp( 71 long expectedInitIkeSpi, 72 int expectedMsgId, 73 boolean expectedUseEncap, 74 String... ikeRespDataFragmentsHex) 75 throws Exception { 76 return awaitReqAndInjectResp( 77 expectedInitIkeSpi, 78 expectedMsgId, 79 expectedUseEncap, 80 1 /* expectedReqPktCnt */, 81 ikeRespDataFragmentsHex) 82 .get(0); 83 } 84 85 /** 86 * Await the expected IKE request (or the list of IKE request fragments) and inject an IKE 87 * response (or a list of response fragments) 88 * 89 * @param ikeRespDataFragmentsHex IKE response hex (or a list of response fragments) without 90 * IP/UDP headers or NON ESP MARKER. 91 */ awaitReqAndInjectResp( long expectedInitIkeSpi, int expectedMsgId, boolean expectedUseEncap, int expectedReqPktCnt, String... ikeRespDataFragmentsHex)92 public List<byte[]> awaitReqAndInjectResp( 93 long expectedInitIkeSpi, 94 int expectedMsgId, 95 boolean expectedUseEncap, 96 int expectedReqPktCnt, 97 String... ikeRespDataFragmentsHex) 98 throws Exception { 99 List<byte[]> reqList = new ArrayList<>(expectedReqPktCnt); 100 if (expectedReqPktCnt == 1) { 101 // Expecting one complete IKE packet 102 byte[] req = 103 awaitIkePacket( 104 (pkt) -> { 105 return isExpectedIkePkt( 106 pkt, 107 expectedInitIkeSpi, 108 expectedMsgId, 109 false /* expectedResp */, 110 expectedUseEncap); 111 }); 112 reqList.add(req); 113 } else { 114 // Expecting "expectedReqPktCnt" number of request fragments 115 for (int i = 0; i < expectedReqPktCnt; i++) { 116 // IKE Fragment number always starts from 1 117 int expectedFragNum = i + 1; 118 byte[] req = 119 awaitIkePacket( 120 (pkt) -> { 121 return isExpectedIkeFragPkt( 122 pkt, 123 expectedInitIkeSpi, 124 expectedMsgId, 125 false /* expectedResp */, 126 expectedUseEncap, 127 expectedFragNum); 128 }); 129 reqList.add(req); 130 } 131 } 132 133 // All request fragments have the same addresses and ports 134 byte[] request = reqList.get(0); 135 136 // Build response header by flipping address and port 137 InetAddress srcAddr = getAddress(request, false /* shouldGetSource */); 138 InetAddress dstAddr = getAddress(request, true /* shouldGetSource */); 139 int srcPort = getPort(request, false /* shouldGetSource */); 140 int dstPort = getPort(request, true /* shouldGetSource */); 141 for (String resp : ikeRespDataFragmentsHex) { 142 byte[] response = 143 buildIkePacket( 144 srcAddr, 145 dstAddr, 146 srcPort, 147 dstPort, 148 expectedUseEncap, 149 hexStringToByteArray(resp)); 150 injectPacket(response); 151 } 152 153 return reqList; 154 } 155 156 /** Await the expected IKE response */ awaitResp(long expectedInitIkeSpi, int expectedMsgId, boolean expectedUseEncap)157 public byte[] awaitResp(long expectedInitIkeSpi, int expectedMsgId, boolean expectedUseEncap) 158 throws Exception { 159 return awaitIkePacket( 160 (pkt) -> { 161 return isExpectedIkePkt( 162 pkt, 163 expectedInitIkeSpi, 164 expectedMsgId, 165 true /* expectedResp*/, 166 expectedUseEncap); 167 }); 168 } 169 awaitIkePacket(Predicate<byte[]> pktVerifier)170 private byte[] awaitIkePacket(Predicate<byte[]> pktVerifier) throws Exception { 171 long endTime = System.currentTimeMillis() + TIMEOUT; 172 int startIndex = 0; 173 synchronized (mPackets) { 174 while (System.currentTimeMillis() < endTime) { 175 byte[] ikePkt = getFirstMatchingPacket(pktVerifier, startIndex); 176 if (ikePkt != null) { 177 return ikePkt; // We've found the packet we're looking for. 178 } 179 180 startIndex = mPackets.size(); 181 182 // Try to prevent waiting too long. If waitTimeout <= 0, we've already hit timeout 183 long waitTimeout = endTime - System.currentTimeMillis(); 184 if (waitTimeout > 0) { 185 mPackets.wait(waitTimeout); 186 } 187 } 188 189 fail("No matching packet found"); 190 } 191 192 throw new IllegalStateException( 193 "Hit an impossible case where fail() didn't throw an exception"); 194 } 195 isExpectedIkePkt( byte[] pkt, long expectedInitIkeSpi, int expectedMsgId, boolean expectedResp, boolean expectedUseEncap)196 private static boolean isExpectedIkePkt( 197 byte[] pkt, 198 long expectedInitIkeSpi, 199 int expectedMsgId, 200 boolean expectedResp, 201 boolean expectedUseEncap) { 202 int ipProtocolOffset = isIpv6(pkt) ? IP6_PROTO_OFFSET : IP4_PROTO_OFFSET; 203 int ikeOffset = getIkeOffset(pkt, expectedUseEncap); 204 205 return pkt[ipProtocolOffset] == IPPROTO_UDP 206 && expectedUseEncap == hasNonEspMarker(pkt) 207 && isExpectedSpiAndMsgId( 208 pkt, ikeOffset, expectedInitIkeSpi, expectedMsgId, expectedResp); 209 } 210 isExpectedIkeFragPkt( byte[] pkt, long expectedInitIkeSpi, int expectedMsgId, boolean expectedResp, boolean expectedUseEncap, int expectedFragNum)211 private static boolean isExpectedIkeFragPkt( 212 byte[] pkt, 213 long expectedInitIkeSpi, 214 int expectedMsgId, 215 boolean expectedResp, 216 boolean expectedUseEncap, 217 int expectedFragNum) { 218 return isExpectedIkePkt( 219 pkt, expectedInitIkeSpi, expectedMsgId, expectedResp, expectedUseEncap) 220 && isExpectedFragNum(pkt, getIkeOffset(pkt, expectedUseEncap), expectedFragNum); 221 } 222 getIkeOffset(byte[] pkt, boolean useEncap)223 private static int getIkeOffset(byte[] pkt, boolean useEncap) { 224 int hdrLen = isIpv6(pkt) ? IP6_HDRLEN : IP4_HDRLEN; 225 int ikeOffset = UDP_HDRLEN + hdrLen; 226 227 // Port 4500 is used during MOBIKE (and a non-ESP marker is added). This is always done, 228 // regardless of whether the IP address is IPv4 or IPv6 229 return useEncap ? ikeOffset + NON_ESP_MARKER_LEN : ikeOffset; 230 } 231 hasNonEspMarker(byte[] pkt)232 private static boolean hasNonEspMarker(byte[] pkt) { 233 ByteBuffer buffer = ByteBuffer.wrap(pkt); 234 int hdrLen = isIpv6(pkt) ? IP6_HDRLEN : IP4_HDRLEN; 235 int ikeOffset = UDP_HDRLEN + hdrLen; 236 if (buffer.remaining() < ikeOffset) return false; 237 238 buffer.get(new byte[ikeOffset]); // Skip IP and UDP header 239 byte[] nonEspMarker = new byte[NON_ESP_MARKER_LEN]; 240 if (buffer.remaining() < NON_ESP_MARKER_LEN) return false; 241 242 buffer.get(nonEspMarker); 243 return Arrays.equals(NON_ESP_MARKER, nonEspMarker); 244 } 245 isExpectedSpiAndMsgId( byte[] pkt, int ikeOffset, long expectedInitIkeSpi, int expectedMsgId, boolean expectedResp)246 private static boolean isExpectedSpiAndMsgId( 247 byte[] pkt, 248 int ikeOffset, 249 long expectedInitIkeSpi, 250 int expectedMsgId, 251 boolean expectedResp) { 252 if (pkt.length <= ikeOffset + IKE_HEADER_LEN) return false; 253 254 ByteBuffer buffer = ByteBuffer.wrap(pkt); 255 buffer.get(new byte[ikeOffset]); // Skip IP, UDP header (and NON_ESP_MARKER) 256 buffer.mark(); // Mark this position so that later we can reset back here 257 258 // Check SPI 259 buffer.get(new byte[IKE_INIT_SPI_OFFSET]); 260 long initSpi = buffer.getLong(); 261 if (expectedInitIkeSpi != initSpi) { 262 return false; 263 } 264 265 // Check direction 266 buffer.reset(); 267 buffer.get(new byte[IKE_IS_RESP_BYTE_OFFSET]); 268 byte flagsByte = buffer.get(); 269 boolean isResp = ((flagsByte & RSP_FLAG_MASK) != 0); 270 if (expectedResp != isResp) { 271 return false; 272 } 273 274 // Check message ID 275 buffer.reset(); 276 buffer.get(new byte[IKE_MSG_ID_OFFSET]); 277 278 // Both the expected message ID and the packet's msgId are signed integers, so directly 279 // compare them. 280 int msgId = buffer.getInt(); 281 if (expectedMsgId != msgId) { 282 return false; 283 } 284 285 return true; 286 } 287 isExpectedFragNum(byte[] pkt, int ikeOffset, int expectedFragNum)288 private static boolean isExpectedFragNum(byte[] pkt, int ikeOffset, int expectedFragNum) { 289 ByteBuffer buffer = ByteBuffer.wrap(pkt); 290 buffer.get(new byte[ikeOffset]); 291 buffer.mark(); // Mark this position so that later we can reset back here 292 293 // Check if it is a fragment packet 294 buffer.get(new byte[IKE_FIRST_PAYLOAD_OFFSET]); 295 int firstPayload = Byte.toUnsignedInt(buffer.get()); 296 if (firstPayload != IKE_PAYLOAD_TYPE_SKF) { 297 return false; 298 } 299 300 // Check fragment number 301 buffer.reset(); 302 buffer.get(new byte[IKE_FRAG_NUM_OFFSET]); 303 int fragNum = Short.toUnsignedInt(buffer.getShort()); 304 return expectedFragNum == fragNum; 305 } 306 307 public static class PortPair { 308 public final int srcPort; 309 public final int dstPort; 310 PortPair(int sourcePort, int destinationPort)311 public PortPair(int sourcePort, int destinationPort) { 312 srcPort = sourcePort; 313 dstPort = destinationPort; 314 } 315 } 316 getSrcDestPortPair(byte[] outboundIkePkt)317 public static PortPair getSrcDestPortPair(byte[] outboundIkePkt) throws Exception { 318 return new PortPair( 319 getPort(outboundIkePkt, true /* shouldGetSource */), 320 getPort(outboundIkePkt, false /* shouldGetSource */)); 321 } 322 getAddress(byte[] pkt, boolean shouldGetSource)323 private static InetAddress getAddress(byte[] pkt, boolean shouldGetSource) throws Exception { 324 int ipLen = isIpv6(pkt) ? IP6_ADDR_LEN : IP4_ADDR_LEN; 325 int srcIpOffset = isIpv6(pkt) ? IP6_ADDR_OFFSET : IP4_ADDR_OFFSET; 326 int ipOffset = shouldGetSource ? srcIpOffset : srcIpOffset + ipLen; 327 328 ByteBuffer buffer = ByteBuffer.wrap(pkt); 329 buffer.get(new byte[ipOffset]); 330 byte[] ipAddrBytes = new byte[ipLen]; 331 buffer.get(ipAddrBytes); 332 return InetAddress.getByAddress(ipAddrBytes); 333 } 334 getPort(byte[] pkt, boolean shouldGetSource)335 private static int getPort(byte[] pkt, boolean shouldGetSource) { 336 ByteBuffer buffer = ByteBuffer.wrap(pkt); 337 int srcPortOffset = isIpv6(pkt) ? IP6_HDRLEN : IP4_HDRLEN; 338 int portOffset = shouldGetSource ? srcPortOffset : srcPortOffset + PORT_LEN; 339 340 buffer.get(new byte[portOffset]); 341 return Short.toUnsignedInt(buffer.getShort()); 342 } 343 buildIkePacket( InetAddress srcAddr, InetAddress dstAddr, int srcPort, int dstPort, boolean useEncap, byte[] ikePacket)344 public static byte[] buildIkePacket( 345 InetAddress srcAddr, 346 InetAddress dstAddr, 347 int srcPort, 348 int dstPort, 349 boolean useEncap, 350 byte[] ikePacket) 351 throws Exception { 352 if (useEncap) { 353 ByteBuffer buffer = ByteBuffer.allocate(NON_ESP_MARKER_LEN + ikePacket.length); 354 buffer.put(NON_ESP_MARKER); 355 buffer.put(ikePacket); 356 ikePacket = buffer.array(); 357 } 358 359 UdpHeader udpPkt = new UdpHeader(srcPort, dstPort, new BytePayload(ikePacket)); 360 IpHeader ipPkt = getIpHeader(udpPkt.getProtocolId(), srcAddr, dstAddr, udpPkt); 361 return ipPkt.getPacketBytes(); 362 } 363 getIpHeader( int protocol, InetAddress src, InetAddress dst, Payload payload)364 private static IpHeader getIpHeader( 365 int protocol, InetAddress src, InetAddress dst, Payload payload) { 366 if ((src instanceof Inet6Address) != (dst instanceof Inet6Address)) { 367 throw new IllegalArgumentException("Invalid src/dst address combination"); 368 } 369 370 if (src instanceof Inet6Address) { 371 return new Ip6Header(protocol, (Inet6Address) src, (Inet6Address) dst, payload); 372 } else { 373 return new Ip4Header(protocol, (Inet4Address) src, (Inet4Address) dst, payload); 374 } 375 } 376 } 377