1 /* 2 * Copyright (C) 2019 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 17 package android.net.ipsec.ike; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.SystemApi; 22 import android.util.ArraySet; 23 24 import com.android.internal.annotations.VisibleForTesting; 25 import com.android.internal.net.ipsec.ike.exceptions.InvalidSyntaxException; 26 27 import java.lang.annotation.Retention; 28 import java.lang.annotation.RetentionPolicy; 29 import java.net.Inet4Address; 30 import java.net.Inet6Address; 31 import java.net.InetAddress; 32 import java.net.UnknownHostException; 33 import java.nio.BufferOverflowException; 34 import java.nio.ByteBuffer; 35 import java.util.Objects; 36 37 /** 38 * IkeTrafficSelector represents a Traffic Selector of a Child Session. 39 * 40 * <p>Traffic Selectors specify addresses that are acceptable within the IPsec SA. 41 * 42 * <p>Callers can propose {@link IkeTrafficSelector}s when building a {@link ChildSessionParams} and 43 * receive the negotiated {@link IkeTrafficSelector}s via a {@link ChildSessionConfiguration}. 44 * 45 * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.13">RFC 7296, Internet Key Exchange 46 * Protocol Version 2 (IKEv2)</a> 47 * @hide 48 */ 49 @SystemApi 50 public final class IkeTrafficSelector { 51 52 // IpProtocolId consists of standard IP Protocol IDs. 53 /** @hide */ 54 @Retention(RetentionPolicy.SOURCE) 55 @IntDef({IP_PROTOCOL_ID_UNSPEC, IP_PROTOCOL_ID_ICMP, IP_PROTOCOL_ID_TCP, IP_PROTOCOL_ID_UDP}) 56 public @interface IpProtocolId {} 57 58 // Zero value is re-defined by IKE to indicate that all IP protocols are acceptable. 59 /** @hide */ 60 @VisibleForTesting static final int IP_PROTOCOL_ID_UNSPEC = 0; 61 /** @hide */ 62 @VisibleForTesting static final int IP_PROTOCOL_ID_ICMP = 1; 63 /** @hide */ 64 @VisibleForTesting static final int IP_PROTOCOL_ID_TCP = 6; 65 /** @hide */ 66 @VisibleForTesting static final int IP_PROTOCOL_ID_UDP = 17; 67 68 private static final ArraySet<Integer> IP_PROTOCOL_ID_SET = new ArraySet<>(); 69 70 static { 71 IP_PROTOCOL_ID_SET.add(IP_PROTOCOL_ID_UNSPEC); 72 IP_PROTOCOL_ID_SET.add(IP_PROTOCOL_ID_ICMP); 73 IP_PROTOCOL_ID_SET.add(IP_PROTOCOL_ID_TCP); 74 IP_PROTOCOL_ID_SET.add(IP_PROTOCOL_ID_UDP); 75 } 76 77 /** 78 * TrafficSelectorType consists of IKE standard Traffic Selector Types. 79 * 80 * @see <a 81 * href="https://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml">Internet 82 * Key Exchange Version 2 (IKEv2) Parameters</a> 83 * @hide 84 */ 85 @Retention(RetentionPolicy.SOURCE) 86 @IntDef({TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE, TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE}) 87 public @interface TrafficSelectorType {} 88 89 /** @hide */ 90 public static final int TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE = 7; 91 /** @hide */ 92 public static final int TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE = 8; 93 94 /** @hide */ 95 public static final int PORT_NUMBER_MIN = 0; 96 /** @hide */ 97 public static final int PORT_NUMBER_MAX = 65535; 98 99 // TODO: Consider defining these constants in a central place in Connectivity. 100 private static final int IPV4_ADDR_LEN = 4; 101 private static final int IPV6_ADDR_LEN = 16; 102 103 @VisibleForTesting static final int TRAFFIC_SELECTOR_IPV4_LEN = 16; 104 @VisibleForTesting static final int TRAFFIC_SELECTOR_IPV6_LEN = 40; 105 106 /** @hide */ 107 public final int tsType; 108 /** @hide */ 109 public final int ipProtocolId; 110 /** @hide */ 111 public final int selectorLength; 112 /** The smallest port number allowed by this Traffic Selector. Informational only. */ 113 public final int startPort; 114 /** The largest port number allowed by this Traffic Selector. Informational only. */ 115 public final int endPort; 116 /** The smallest address included in this Traffic Selector. */ 117 @NonNull public final InetAddress startingAddress; 118 /** The largest address included in this Traffic Selector. */ 119 @NonNull public final InetAddress endingAddress; 120 IkeTrafficSelector( int tsType, int ipProtocolId, int selectorLength, int startPort, int endPort, InetAddress startingAddress, InetAddress endingAddress)121 private IkeTrafficSelector( 122 int tsType, 123 int ipProtocolId, 124 int selectorLength, 125 int startPort, 126 int endPort, 127 InetAddress startingAddress, 128 InetAddress endingAddress) { 129 this.tsType = tsType; 130 this.ipProtocolId = ipProtocolId; 131 this.selectorLength = selectorLength; 132 133 // Ports & Addresses previously validated in decodeIkeTrafficSelectors() 134 this.startPort = startPort; 135 this.endPort = endPort; 136 this.startingAddress = startingAddress; 137 this.endingAddress = endingAddress; 138 } 139 140 /** 141 * Construct an instance of {@link IkeTrafficSelector} for negotiating a Child Session. 142 * 143 * <p>Android platform does not support port-based routing. The port range negotiation is only 144 * informational. 145 * 146 * @param startPort the smallest port number allowed by this Traffic Selector. 147 * @param endPort the largest port number allowed by this Traffic Selector. 148 * @param startingAddress the smallest address included in this Traffic Selector. 149 * @param endingAddress the largest address included in this Traffic Selector. 150 */ IkeTrafficSelector( int startPort, int endPort, @NonNull InetAddress startingAddress, @NonNull InetAddress endingAddress)151 public IkeTrafficSelector( 152 int startPort, 153 int endPort, 154 @NonNull InetAddress startingAddress, 155 @NonNull InetAddress endingAddress) { 156 this(getTsType(startingAddress), startPort, endPort, startingAddress, endingAddress); 157 } 158 getTsType(InetAddress address)159 private static int getTsType(InetAddress address) { 160 if (address instanceof Inet4Address) { 161 return TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE; 162 } 163 return TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE; 164 } 165 166 /** 167 * Construct an instance of IkeTrafficSelector for building an outbound IKE message. 168 * 169 * @param tsType the Traffic Selector type. 170 * @param startPort the smallest port number allowed by this Traffic Selector. 171 * @param endPort the largest port number allowed by this Traffic Selector. 172 * @param startingAddress the smallest address included in this Traffic Selector. 173 * @param endingAddress the largest address included in this Traffic Selector. 174 * @hide 175 */ IkeTrafficSelector( @rafficSelectorType int tsType, int startPort, int endPort, InetAddress startingAddress, InetAddress endingAddress)176 public IkeTrafficSelector( 177 @TrafficSelectorType int tsType, 178 int startPort, 179 int endPort, 180 InetAddress startingAddress, 181 InetAddress endingAddress) { 182 183 this.tsType = tsType; 184 this.ipProtocolId = IP_PROTOCOL_ID_UNSPEC; 185 186 switch (tsType) { 187 case TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE: 188 this.selectorLength = TRAFFIC_SELECTOR_IPV4_LEN; 189 190 if (!(startingAddress instanceof Inet4Address) 191 || !(endingAddress instanceof Inet4Address)) { 192 throw new IllegalArgumentException( 193 "Invalid address range: TS_IPV4_ADDR_RANGE requires IPv4 addresses."); 194 } 195 196 break; 197 case TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE: 198 this.selectorLength = TRAFFIC_SELECTOR_IPV6_LEN; 199 200 if (!(startingAddress instanceof Inet6Address) 201 || !(endingAddress instanceof Inet6Address)) { 202 throw new IllegalArgumentException( 203 "Invalid address range: TS_IPV6_ADDR_RANGE requires IPv6 addresses."); 204 } 205 break; 206 default: 207 throw new IllegalArgumentException("Unrecognized Traffic Selector type."); 208 } 209 210 if (compareInetAddressTo(startingAddress, endingAddress) > 0) { 211 throw new IllegalArgumentException("Received invalid address range."); 212 } 213 214 if (!isPortRangeValid(startPort, endPort)) { 215 throw new IllegalArgumentException( 216 "Invalid port range. startPort: " + startPort + " endPort: " + endPort); 217 } 218 219 this.startPort = startPort; 220 this.endPort = endPort; 221 this.startingAddress = startingAddress; 222 this.endingAddress = endingAddress; 223 } 224 225 /** 226 * Decode IkeTrafficSelectors from inbound Traffic Selector Payload. 227 * 228 * <p>This method is only called by IkeTsPayload when decoding inbound IKE message. 229 * 230 * @param numTs number or Traffic Selectors 231 * @param tsBytes encoded byte array of Traffic Selectors 232 * @return an array of decoded IkeTrafficSelectors 233 * @throws InvalidSyntaxException if received bytes are malformed. 234 * @hide 235 */ decodeIkeTrafficSelectors(int numTs, byte[] tsBytes)236 public static IkeTrafficSelector[] decodeIkeTrafficSelectors(int numTs, byte[] tsBytes) 237 throws InvalidSyntaxException { 238 IkeTrafficSelector[] tsArray = new IkeTrafficSelector[numTs]; 239 ByteBuffer inputBuffer = ByteBuffer.wrap(tsBytes); 240 241 try { 242 for (int i = 0; i < numTs; i++) { 243 int tsType = Byte.toUnsignedInt(inputBuffer.get()); 244 switch (tsType) { 245 case TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE: 246 tsArray[i] = decodeTrafficSelector(inputBuffer, 247 TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE); 248 break; 249 case TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE: 250 tsArray[i] = decodeTrafficSelector(inputBuffer, 251 TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE); 252 break; 253 default: 254 throw new InvalidSyntaxException( 255 "Invalid Traffic Selector type: " + tsType); 256 } 257 } 258 } catch (BufferOverflowException e) { 259 // Throw exception if any Traffic Selector has invalid length. 260 throw new InvalidSyntaxException(e); 261 } 262 263 if (inputBuffer.remaining() != 0) { 264 throw new InvalidSyntaxException( 265 "Unexpected trailing characters of Traffic Selectors."); 266 } 267 268 return tsArray; 269 } 270 271 // Decode Traffic Selector from a ByteBuffer. A BufferOverflowException will be thrown and 272 // caught by method caller if operation reaches the input ByteBuffer's limit. decodeTrafficSelector(ByteBuffer inputBuffer, int tsType)273 private static IkeTrafficSelector decodeTrafficSelector(ByteBuffer inputBuffer, int tsType) 274 throws InvalidSyntaxException { 275 // Decode and validate IP Protocol ID 276 int ipProtocolId = Byte.toUnsignedInt(inputBuffer.get()); 277 if (!IP_PROTOCOL_ID_SET.contains(ipProtocolId)) { 278 throw new InvalidSyntaxException("Invalid IP Protocol ID."); 279 } 280 281 // Decode and validate Selector Length 282 boolean isTsIpv4 = tsType == TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE; 283 int expectedTsLen = isTsIpv4 ? TRAFFIC_SELECTOR_IPV4_LEN : TRAFFIC_SELECTOR_IPV6_LEN; 284 int tsLength = Short.toUnsignedInt(inputBuffer.getShort()); 285 if (expectedTsLen != tsLength) { 286 throw new InvalidSyntaxException("Invalid Traffic Selector Length."); 287 } 288 289 // Decode and validate ports 290 int startPort = Short.toUnsignedInt(inputBuffer.getShort()); 291 int endPort = Short.toUnsignedInt(inputBuffer.getShort()); 292 if (!isPortRangeValid(startPort, endPort)) { 293 throw new InvalidSyntaxException( 294 "Received invalid port range. startPort: " 295 + startPort 296 + " endPort: " 297 + endPort); 298 } 299 300 // Decode and validate IP addresses 301 int expectedAddrLen = isTsIpv4 ? IPV4_ADDR_LEN : IPV6_ADDR_LEN; 302 byte[] startAddressBytes = new byte[expectedAddrLen]; 303 byte[] endAddressBytes = new byte[expectedAddrLen]; 304 inputBuffer.get(startAddressBytes); 305 inputBuffer.get(endAddressBytes); 306 try { 307 InetAddress startAddress = InetAddress.getByAddress(startAddressBytes); 308 InetAddress endAddress = InetAddress.getByAddress(endAddressBytes); 309 310 boolean isStartAddrIpv4 = startAddress instanceof Inet4Address; 311 boolean isEndAddrIpv4 = endAddress instanceof Inet4Address; 312 if (isTsIpv4 != isStartAddrIpv4 || isTsIpv4 != isEndAddrIpv4) { 313 throw new InvalidSyntaxException("Invalid IP address family"); 314 } 315 316 // Validate address range. 317 if (compareInetAddressTo(startAddress, endAddress) > 0) { 318 throw new InvalidSyntaxException("Received invalid IP address range."); 319 } 320 321 return new IkeTrafficSelector( 322 tsType, 323 ipProtocolId, 324 expectedTsLen, 325 startPort, 326 endPort, 327 startAddress, 328 endAddress); 329 } catch (ClassCastException | UnknownHostException | IllegalArgumentException e) { 330 throw new InvalidSyntaxException(e); 331 } 332 } 333 334 // Validate port range. isPortRangeValid(int startPort, int endPort)335 private static boolean isPortRangeValid(int startPort, int endPort) { 336 return (startPort >= PORT_NUMBER_MIN 337 && startPort <= PORT_NUMBER_MAX 338 && endPort >= PORT_NUMBER_MIN 339 && endPort <= PORT_NUMBER_MAX 340 && startPort <= endPort); 341 } 342 343 // Compare two InetAddresses. Return -1 if the first input is smaller; 1 if the second input is 344 // smaller; 0 if two addresses are equal. 345 // TODO: Consider moving it to the platform code in the future./ compareInetAddressTo(InetAddress leftAddress, InetAddress rightAddress)346 private static int compareInetAddressTo(InetAddress leftAddress, InetAddress rightAddress) { 347 byte[] leftAddrBytes = leftAddress.getAddress(); 348 byte[] rightAddrBytes = rightAddress.getAddress(); 349 350 if (leftAddrBytes.length != rightAddrBytes.length) { 351 throw new IllegalArgumentException("Two addresses are different types."); 352 } 353 354 for (int i = 0; i < leftAddrBytes.length; i++) { 355 int unsignedByteLeft = Byte.toUnsignedInt(leftAddrBytes[i]); 356 int unsignedByteRight = Byte.toUnsignedInt(rightAddrBytes[i]); 357 358 int result = Integer.compare(unsignedByteLeft, unsignedByteRight); 359 if (result != 0) return result; 360 } 361 return 0; 362 } 363 364 /** 365 * Check if the input IkeTrafficSelector is a subset of this instance. 366 * 367 * @param ts the provided IkeTrafficSelector to check. 368 * @return true if the input IkeTrafficSelector is a subset of this instance, otherwise false. 369 * @hide 370 */ contains(IkeTrafficSelector ts)371 public boolean contains(IkeTrafficSelector ts) { 372 if (tsType == ts.tsType 373 && ipProtocolId == ts.ipProtocolId 374 && startPort <= ts.startPort 375 && endPort >= ts.endPort 376 && compareInetAddressTo(startingAddress, ts.startingAddress) <= 0 377 && compareInetAddressTo(endingAddress, ts.endingAddress) >= 0) { 378 return true; 379 } 380 return false; 381 } 382 383 /** @hide */ 384 @Override hashCode()385 public int hashCode() { 386 return Objects.hash( 387 tsType, 388 ipProtocolId, 389 selectorLength, 390 startPort, 391 endPort, 392 startingAddress, 393 endingAddress); 394 } 395 396 /** @hide */ 397 @Override equals(Object o)398 public boolean equals(Object o) { 399 if (!(o instanceof IkeTrafficSelector)) return false; 400 401 IkeTrafficSelector other = (IkeTrafficSelector) o; 402 403 if (tsType != other.tsType 404 || ipProtocolId != other.ipProtocolId 405 || startPort != other.startPort 406 || endPort != other.endPort) { 407 return false; 408 } 409 410 switch (tsType) { 411 case TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE: 412 return (((Inet4Address) startingAddress) 413 .equals((Inet4Address) other.startingAddress) 414 && ((Inet4Address) endingAddress) 415 .equals((Inet4Address) other.endingAddress)); 416 case TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE: 417 return (((Inet6Address) startingAddress) 418 .equals((Inet6Address) other.startingAddress) 419 && ((Inet6Address) endingAddress) 420 .equals((Inet6Address) other.endingAddress)); 421 default: 422 throw new UnsupportedOperationException("Unrecognized TS type"); 423 } 424 } 425 426 /** 427 * Encode traffic selector to ByteBuffer. 428 * 429 * <p>This method will be only called by IkeTsPayload for building an outbound IKE message. 430 * 431 * @param byteBuffer destination ByteBuffer that stores encoded traffic selector. 432 * @hide 433 */ encodeToByteBuffer(ByteBuffer byteBuffer)434 public void encodeToByteBuffer(ByteBuffer byteBuffer) { 435 byteBuffer 436 .put((byte) tsType) 437 .put((byte) ipProtocolId) 438 .putShort((short) selectorLength) 439 .putShort((short) startPort) 440 .putShort((short) endPort) 441 .put(startingAddress.getAddress()) 442 .put(endingAddress.getAddress()); 443 } 444 } 445