• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_APPLICATION_VERSION;
20 import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_IP4_PCSCF;
21 import static com.android.internal.net.ipsec.ike.message.IkeConfigPayload.CONFIG_ATTR_IP6_PCSCF;
22 
23 import android.annotation.IntDef;
24 import android.annotation.NonNull;
25 import android.annotation.SuppressLint;
26 import android.annotation.SystemApi;
27 
28 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload;
29 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttribute;
30 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeAppVersion;
31 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Pcscf;
32 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Pcscf;
33 
34 import java.lang.annotation.Retention;
35 import java.lang.annotation.RetentionPolicy;
36 import java.net.InetAddress;
37 import java.util.ArrayList;
38 import java.util.Collections;
39 import java.util.HashSet;
40 import java.util.List;
41 import java.util.Objects;
42 import java.util.Set;
43 
44 /**
45  * IkeSessionConfiguration represents the negotiated configuration for a {@link IkeSession}.
46  *
47  * <p>Configurations include remote application version and enabled IKE extensions.
48  */
49 public final class IkeSessionConfiguration {
50     /** @hide */
51     @Retention(RetentionPolicy.SOURCE)
52     @IntDef({EXTENSION_TYPE_FRAGMENTATION, EXTENSION_TYPE_MOBIKE})
53     public @interface ExtensionType {}
54 
55     /** IKE Message Fragmentation */
56     public static final int EXTENSION_TYPE_FRAGMENTATION = 1;
57     /** IKEv2 Mobility and Multihoming Protocol */
58     public static final int EXTENSION_TYPE_MOBIKE = 2;
59 
60     private static final int VALID_EXTENSION_MIN = EXTENSION_TYPE_FRAGMENTATION;
61     private static final int VALID_EXTENSION_MAX = EXTENSION_TYPE_MOBIKE;
62 
63     private final String mRemoteApplicationVersion;
64     private final IkeSessionConnectionInfo mIkeConnInfo;
65     private final List<InetAddress> mPcscfServers = new ArrayList<>();
66     private final List<byte[]> mRemoteVendorIds = new ArrayList<>();
67     private final Set<Integer> mEnabledExtensions = new HashSet<>();
68 
69     /**
70      * Construct an instance of {@link IkeSessionConfiguration}.
71      *
72      * <p>IkeSessionConfigurations may contain negotiated configuration information that is included
73      * in a Configure(Reply) Payload. Thus the input configPayload should always be a
74      * Configure(Reply), and never be a Configure(Request).
75      *
76      * @hide
77      */
IkeSessionConfiguration( IkeSessionConnectionInfo ikeConnInfo, IkeConfigPayload configPayload, List<byte[]> remoteVendorIds, List<Integer> enabledExtensions)78     public IkeSessionConfiguration(
79             IkeSessionConnectionInfo ikeConnInfo,
80             IkeConfigPayload configPayload,
81             List<byte[]> remoteVendorIds,
82             List<Integer> enabledExtensions) {
83         mIkeConnInfo = ikeConnInfo;
84         mRemoteVendorIds.addAll(remoteVendorIds);
85         mEnabledExtensions.addAll(enabledExtensions);
86 
87         String appVersion = "";
88         if (configPayload != null) {
89             if (configPayload.configType != IkeConfigPayload.CONFIG_TYPE_REPLY) {
90                 throw new IllegalArgumentException(
91                         "Cannot build IkeSessionConfiguration with configuration type: "
92                                 + configPayload.configType);
93             }
94 
95             for (ConfigAttribute attr : configPayload.recognizedAttributeList) {
96                 if (attr.isEmptyValue()) continue;
97                 switch (attr.attributeType) {
98                     case CONFIG_ATTR_APPLICATION_VERSION:
99                         ConfigAttributeAppVersion appVersionAttr = (ConfigAttributeAppVersion) attr;
100                         appVersion = appVersionAttr.applicationVersion;
101                         break;
102                     case CONFIG_ATTR_IP4_PCSCF:
103                         ConfigAttributeIpv4Pcscf ip4Pcscf = (ConfigAttributeIpv4Pcscf) attr;
104                         mPcscfServers.add(ip4Pcscf.getAddress());
105                         break;
106                     case CONFIG_ATTR_IP6_PCSCF:
107                         ConfigAttributeIpv6Pcscf ip6Pcscf = (ConfigAttributeIpv6Pcscf) attr;
108                         mPcscfServers.add(ip6Pcscf.getAddress());
109                         break;
110                     default:
111                         // Not relevant to IKE session
112                 }
113             }
114         }
115         mRemoteApplicationVersion = appVersion;
116         validateOrThrow();
117     }
118 
119     /**
120      * Construct an instance of {@link IkeSessionConfiguration}.
121      *
122      * @hide
123      */
IkeSessionConfiguration( IkeSessionConnectionInfo ikeConnInfo, List<InetAddress> pcscfServers, List<byte[]> remoteVendorIds, Set<Integer> enabledExtensions, String remoteApplicationVersion)124     private IkeSessionConfiguration(
125             IkeSessionConnectionInfo ikeConnInfo,
126             List<InetAddress> pcscfServers,
127             List<byte[]> remoteVendorIds,
128             Set<Integer> enabledExtensions,
129             String remoteApplicationVersion) {
130         mIkeConnInfo = ikeConnInfo;
131         mPcscfServers.addAll(pcscfServers);
132         mRemoteVendorIds.addAll(remoteVendorIds);
133         mEnabledExtensions.addAll(enabledExtensions);
134         mRemoteApplicationVersion = remoteApplicationVersion;
135 
136         validateOrThrow();
137     }
138 
validateOrThrow()139     private void validateOrThrow() {
140         String errMsg = " was null";
141         Objects.requireNonNull(mIkeConnInfo, "ikeConnInfo" + errMsg);
142         Objects.requireNonNull(mPcscfServers, "pcscfServers" + errMsg);
143         Objects.requireNonNull(mRemoteVendorIds, "remoteVendorIds" + errMsg);
144         Objects.requireNonNull(mRemoteApplicationVersion, "remoteApplicationVersion" + errMsg);
145         Objects.requireNonNull(mRemoteVendorIds, "remoteVendorIds" + errMsg);
146     }
147 
148     /**
149      * Gets remote (server) version information.
150      *
151      * @return application version of the remote server, or an empty string if the remote server did
152      *     not provide the application version.
153      */
154     @NonNull
getRemoteApplicationVersion()155     public String getRemoteApplicationVersion() {
156         return mRemoteApplicationVersion;
157     }
158 
159     /**
160      * Returns remote vendor IDs received during IKE Session setup.
161      *
162      * <p>According to the IKEv2 specification (RFC 7296), a vendor ID may indicate the sender is
163      * capable of accepting certain extensions to the protocol, or it may simply identify the
164      * implementation as an aid in debugging.
165      *
166      * @return the vendor IDs of the remote server, or an empty list if no vendor ID is received
167      *     during IKE Session setup.
168      */
169     @NonNull
getRemoteVendorIds()170     public List<byte[]> getRemoteVendorIds() {
171         return Collections.unmodifiableList(mRemoteVendorIds);
172     }
173 
174     /**
175      * Checks if an IKE extension is enabled.
176      *
177      * <p>An IKE extension is enabled when both sides can support it. This negotiation always
178      * happens in IKE initial exchanges (IKE INIT and IKE AUTH).
179      *
180      * @param extensionType the extension type.
181      * @return {@code true} if this extension is enabled.
182      */
isIkeExtensionEnabled(@xtensionType int extensionType)183     public boolean isIkeExtensionEnabled(@ExtensionType int extensionType) {
184         return mEnabledExtensions.contains(extensionType);
185     }
186 
187     /**
188      * Returns the assigned P_CSCF servers.
189      *
190      * @return the assigned P_CSCF servers, or an empty list when no servers are assigned by the
191      *     remote IKE server.
192      * @hide
193      */
194     @SystemApi
195     @NonNull
getPcscfServers()196     public List<InetAddress> getPcscfServers() {
197         return Collections.unmodifiableList(mPcscfServers);
198     }
199 
200     /**
201      * Returns the connection information.
202      *
203      * @return the IKE Session connection information.
204      */
205     @NonNull
getIkeSessionConnectionInfo()206     public IkeSessionConnectionInfo getIkeSessionConnectionInfo() {
207         return mIkeConnInfo;
208     }
209 
210     /**
211      * This class can be used to incrementally construct a {@link IkeSessionConfiguration}.
212      *
213      * <p>Except for testing, IKE library users normally do not instantiate {@link
214      * IkeSessionConfiguration} themselves but instead get a reference via {@link
215      * IkeSessionCallback}
216      */
217     public static final class Builder {
218         private final IkeSessionConnectionInfo mIkeConnInfo;
219         private final List<InetAddress> mPcscfServers = new ArrayList<>();
220         private final List<byte[]> mRemoteVendorIds = new ArrayList<>();
221         private final Set<Integer> mEnabledExtensions = new HashSet<>();
222         private String mRemoteApplicationVersion = "";
223 
224         /**
225          * Constructs a Builder.
226          *
227          * @param ikeConnInfo the connection information
228          */
Builder(@onNull IkeSessionConnectionInfo ikeConnInfo)229         public Builder(@NonNull IkeSessionConnectionInfo ikeConnInfo) {
230             Objects.requireNonNull(ikeConnInfo, "ikeConnInfo was null");
231             mIkeConnInfo = ikeConnInfo;
232         }
233 
234         /**
235          * Adds an assigned P_CSCF server for the {@link IkeSessionConfiguration} being built.
236          *
237          * @param pcscfServer an assigned P_CSCF server
238          * @return Builder this, to facilitate chaining
239          * @hide
240          */
241         @SystemApi
242         @NonNull
addPcscfServer(@onNull InetAddress pcscfServer)243         public Builder addPcscfServer(@NonNull InetAddress pcscfServer) {
244             Objects.requireNonNull(pcscfServer, "pcscfServer was null");
245             mPcscfServers.add(pcscfServer);
246             return this;
247         }
248 
249         /**
250          * Clear all P_CSCF servers from the {@link IkeSessionConfiguration} being built.
251          *
252          * @return Builder this, to facilitate chaining
253          * @hide
254          */
255         @SystemApi
256         @NonNull
clearPcscfServers()257         public Builder clearPcscfServers() {
258             mPcscfServers.clear();
259             return this;
260         }
261 
262         /**
263          * Adds a remote vendor ID for the {@link IkeSessionConfiguration} being built.
264          *
265          * @param remoteVendorId a remote vendor ID
266          * @return Builder this, to facilitate chaining
267          */
268         @NonNull
addRemoteVendorId(@onNull byte[] remoteVendorId)269         public Builder addRemoteVendorId(@NonNull byte[] remoteVendorId) {
270             Objects.requireNonNull(remoteVendorId, "remoteVendorId was null");
271             mRemoteVendorIds.add(remoteVendorId);
272             return this;
273         }
274 
275         /**
276          * Clears all remote vendor IDs from the {@link IkeSessionConfiguration} being built.
277          *
278          * @return Builder this, to facilitate chaining
279          */
280         @NonNull
clearRemoteVendorIds()281         public Builder clearRemoteVendorIds() {
282             mRemoteVendorIds.clear();
283             return this;
284         }
285 
286         /**
287          * Sets the remote application version for the {@link IkeSessionConfiguration} being built.
288          *
289          * @param remoteApplicationVersion the remote application version. Defaults to an empty
290          *     string.
291          * @return Builder this, to facilitate chaining
292          */
293         @NonNull
setRemoteApplicationVersion(@onNull String remoteApplicationVersion)294         public Builder setRemoteApplicationVersion(@NonNull String remoteApplicationVersion) {
295             Objects.requireNonNull(remoteApplicationVersion, "remoteApplicationVersion was null");
296             mRemoteApplicationVersion = remoteApplicationVersion;
297             return this;
298         }
299 
300         /**
301          * Clears the remote application version from the {@link IkeSessionConfiguration} being
302          * built.
303          *
304          * @return Builder this, to facilitate chaining
305          */
306         @NonNull
clearRemoteApplicationVersion()307         public Builder clearRemoteApplicationVersion() {
308             mRemoteApplicationVersion = "";
309             return this;
310         }
311 
validateExtensionOrThrow(@xtensionType int extensionType)312         private static void validateExtensionOrThrow(@ExtensionType int extensionType) {
313             if (extensionType >= VALID_EXTENSION_MIN && extensionType <= VALID_EXTENSION_MAX) {
314                 return;
315             }
316             throw new IllegalArgumentException("Invalid extension type: " + extensionType);
317         }
318 
319         /**
320          * Marks an IKE extension as enabled for the {@link IkeSessionConfiguration} being built.
321          *
322          * @param extensionType the enabled extension
323          * @return Builder this, to facilitate chaining
324          */
325         // MissingGetterMatchingBuilder: Use #isIkeExtensionEnabled instead of #getIkeExtension
326         // because #isIkeExtensionEnabled allows callers to check the presence of an IKE extension
327         // more easily
328         @SuppressLint("MissingGetterMatchingBuilder")
329         @NonNull
addIkeExtension(@xtensionType int extensionType)330         public Builder addIkeExtension(@ExtensionType int extensionType) {
331             validateExtensionOrThrow(extensionType);
332             mEnabledExtensions.add(extensionType);
333             return this;
334         }
335 
336         /**
337          * Clear all enabled IKE extensions from the {@link IkeSessionConfiguration} being built.
338          *
339          * @return Builder this, to facilitate chaining
340          */
341         @NonNull
clearIkeExtensions()342         public Builder clearIkeExtensions() {
343             mEnabledExtensions.clear();
344             return this;
345         }
346 
347         /** Constructs an {@link IkeSessionConfiguration} instance. */
348         @NonNull
build()349         public IkeSessionConfiguration build() {
350             return new IkeSessionConfiguration(
351                     mIkeConnInfo,
352                     mPcscfServers,
353                     mRemoteVendorIds,
354                     mEnabledExtensions,
355                     mRemoteApplicationVersion);
356         }
357     }
358 }
359