blob: baebe64733d156069605be9b64ccbf38e562ac9c [file] [log] [blame]
evitayan68fde6e2019-02-15 16:06:02 -08001/*
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
17package com.android.ike.ikev2;
18
19import android.annotation.IntDef;
20import android.util.ArraySet;
21
22import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
23import com.android.internal.annotations.VisibleForTesting;
24
25import java.lang.annotation.Retention;
26import java.lang.annotation.RetentionPolicy;
27import java.net.Inet4Address;
28import java.net.InetAddress;
29import java.net.UnknownHostException;
30import java.nio.BufferOverflowException;
31import java.nio.ByteBuffer;
32
33/**
34 * IkeTrafficSelector represents a Traffic Selector of a Child SA.
35 *
36 * <p>IkeTrafficSelector can be constructed by users for initiating Create Child exchange or be
37 * constructed from a decoded inbound Traffic Selector Payload.
38 *
39 * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.13">RFC 7296, Internet Key Exchange
40 * Protocol Version 2 (IKEv2)</a>
41 */
42public final class IkeTrafficSelector {
43
44 // IpProtocolId consists of standard IP Protocol IDs.
45 @Retention(RetentionPolicy.SOURCE)
46 @IntDef({IP_PROTOCOL_ID_UNSPEC, IP_PROTOCOL_ID_ICMP, IP_PROTOCOL_ID_TCP, IP_PROTOCOL_ID_UCP})
47 public @interface IpProtocolId {}
48
49 // Zero value is re-defined by IKE to indicate that all IP protocols are acceptable.
50 @VisibleForTesting static final int IP_PROTOCOL_ID_UNSPEC = 0;
51 @VisibleForTesting static final int IP_PROTOCOL_ID_ICMP = 1;
52 @VisibleForTesting static final int IP_PROTOCOL_ID_TCP = 6;
53 @VisibleForTesting static final int IP_PROTOCOL_ID_UCP = 17;
54
55 private static final ArraySet<Integer> IP_PROTOCOL_ID_SET = new ArraySet<>();
56
57 static {
58 IP_PROTOCOL_ID_SET.add(IP_PROTOCOL_ID_UNSPEC);
59 IP_PROTOCOL_ID_SET.add(IP_PROTOCOL_ID_ICMP);
60 IP_PROTOCOL_ID_SET.add(IP_PROTOCOL_ID_TCP);
61 IP_PROTOCOL_ID_SET.add(IP_PROTOCOL_ID_UCP);
62 }
63
64 /**
65 * TrafficSelectorType consists of IKE standard Traffic Selector Types.
66 *
67 * @see <a
68 * href="https://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml">Internet
69 * Key Exchange Version 2 (IKEv2) Parameters</a>
70 */
71 @Retention(RetentionPolicy.SOURCE)
72 @IntDef({TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE, TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE})
73 public @interface TrafficSelectorType {}
74
75 public static final int TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE = 7;
76 public static final int TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE = 8;
77
78 // TODO: Consider defining these constants in a central place in Connectivity.
79 private static final int IPV4_ADDR_LEN = 4;
80 private static final int IPV6_ADDR_LEN = 16;
81
82 @VisibleForTesting static final int TRAFFIC_SELECTOR_IPV4_LEN = 16;
83 @VisibleForTesting static final int TRAFFIC_SELECTOR_IPV6_LEN = 40;
84
85 public final int tsType;
86 public final int ipProtocolId;
87 public final int selectorLength;
88 public final int startPort;
89 public final int endPort;
90 public final InetAddress startingAddress;
91 public final InetAddress endingAddress;
92
93 private IkeTrafficSelector(
94 int tsType,
95 int ipProtocolId,
96 int selectorLength,
97 int startPort,
98 int endPort,
99 InetAddress startingAddress,
100 InetAddress endingAddress) {
101 this.tsType = tsType;
102 this.ipProtocolId = ipProtocolId;
103 this.selectorLength = selectorLength;
104 this.startPort = startPort;
105 this.endPort = endPort;
106 this.startingAddress = startingAddress;
107 this.endingAddress = endingAddress;
108 }
109
110 // TODO: Add a constructor for users to construct IkeTrafficSelector.
111
112 /**
113 * Decode IkeTrafficSelectors from inbound Traffic Selector Payload.
114 *
115 * <p>This method is only called by IkeTsPayload when decoding inbound IKE message.
116 *
117 * @param numTs number or Traffic Selectors
118 * @param tsBytes encoded byte array of Traffic Selectors
119 * @return an array of decoded IkeTrafficSelectors
120 * @throws InvalidSyntaxException if received bytes are malformed.
121 */
122 public static IkeTrafficSelector[] decodeIkeTrafficSelectors(int numTs, byte[] tsBytes)
123 throws InvalidSyntaxException {
124 IkeTrafficSelector[] tsArray = new IkeTrafficSelector[numTs];
125 ByteBuffer inputBuffer = ByteBuffer.wrap(tsBytes);
126
127 try {
128 for (int i = 0; i < numTs; i++) {
129 int tsType = Byte.toUnsignedInt(inputBuffer.get());
130 switch (tsType) {
131 case TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE:
132 tsArray[i] = decodeIpv4TrafficSelector(inputBuffer);
133 break;
134 case TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE:
135 // TODO: Support it.
136 throw new UnsupportedOperationException("Cannot decode this type.");
137 default:
138 throw new InvalidSyntaxException(
139 "Invalid Traffic Selector type: " + tsType);
140 }
141 }
142 } catch (BufferOverflowException e) {
143 // Throw exception if any Traffic Selector has invalid length.
144 throw new InvalidSyntaxException(e);
145 }
146
147 if (inputBuffer.remaining() != 0) {
148 throw new InvalidSyntaxException(
149 "Unexpected trailing characters of Traffic Selectors.");
150 }
151
152 return tsArray;
153 }
154
155 // Decode Traffic Selector using IPv4 address range from a ByteBuffer. A BufferOverflowException
156 // will be thrown and caught by method caller if operation reaches the input ByteBuffer's limit.
157 private static IkeTrafficSelector decodeIpv4TrafficSelector(ByteBuffer inputBuffer)
158 throws InvalidSyntaxException {
159 // Decode and validate IP Protocol ID
160 int ipProtocolId = Byte.toUnsignedInt(inputBuffer.get());
161 if (!IP_PROTOCOL_ID_SET.contains(ipProtocolId)) {
162 throw new InvalidSyntaxException("Invalid IP Protocol ID.");
163 }
164
165 // Decode and validate Selector Length
166 int tsLength = Short.toUnsignedInt(inputBuffer.getShort());
167 if (TRAFFIC_SELECTOR_IPV4_LEN != tsLength) {
168 throw new InvalidSyntaxException("Invalid Traffic Selector Length.");
169 }
170
171 // Decode and validate ports
172 int startPort = Short.toUnsignedInt(inputBuffer.getShort());
173 int endPort = Short.toUnsignedInt(inputBuffer.getShort());
174 if (startPort > endPort) {
175 throw new InvalidSyntaxException("Received invalid port range.");
176 }
177
178 // Decode and validate IPv4 addresses
179 byte[] startAddressBytes = new byte[IPV4_ADDR_LEN];
180 byte[] endAddressBytes = new byte[IPV4_ADDR_LEN];
181 inputBuffer.get(startAddressBytes);
182 inputBuffer.get(endAddressBytes);
183 try {
184 Inet4Address startAddress =
185 (Inet4Address) (Inet4Address.getByAddress(startAddressBytes));
186 Inet4Address endAddress = (Inet4Address) (Inet4Address.getByAddress(endAddressBytes));
187
188 // Validate address range.
189 if (!isInetAddressRangeValid(startAddress, endAddress)) {
190 throw new InvalidSyntaxException("Received invalid IPv4 address range.");
191 }
192
193 return new IkeTrafficSelector(
194 TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE,
195 ipProtocolId,
196 TRAFFIC_SELECTOR_IPV4_LEN,
197 startPort,
198 endPort,
199 startAddress,
200 endAddress);
201 } catch (ClassCastException | UnknownHostException | IllegalArgumentException e) {
202 throw new InvalidSyntaxException(e);
203 }
204 }
205
206 // TODO: Add a method for decoding IPv6 traffic selector.
207
208 // Validate address range. Caller must ensure two address are same types.
209 // TODO: Consider moving it to the platform code in the future.
210 private static boolean isInetAddressRangeValid(
211 InetAddress startAddress, InetAddress endAddress) {
212 byte[] startAddrBytes = startAddress.getAddress();
213 byte[] endAddrBytes = endAddress.getAddress();
214
215 if (startAddrBytes.length != endAddrBytes.length) {
216 throw new IllegalArgumentException("Two addresses are different types.");
217 }
218
219 for (int i = 0; i < startAddrBytes.length; i++) {
220 int unsignedByteStart = Byte.toUnsignedInt(startAddrBytes[i]);
221 int unsignedByteEnd = Byte.toUnsignedInt(endAddrBytes[i]);
222
223 if (unsignedByteStart < unsignedByteEnd) {
224 return true;
225 } else if (unsignedByteStart > unsignedByteEnd) {
226 return false;
227 }
228 }
229 return true;
230 }
231}