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 android.system.OsConstants.AF_INET;
20 import static android.system.OsConstants.AF_INET6;
21 
22 import android.annotation.IntDef;
23 import android.annotation.IntRange;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.annotation.SuppressLint;
27 import android.annotation.SystemApi;
28 import android.content.Context;
29 import android.net.ConnectivityManager;
30 import android.net.Network;
31 import android.net.eap.EapSessionConfig;
32 
33 import com.android.internal.annotations.VisibleForTesting;
34 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv4Pcscf;
35 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.ConfigAttributeIpv6Pcscf;
36 import com.android.internal.net.ipsec.ike.message.IkeConfigPayload.IkeConfigAttribute;
37 import com.android.internal.net.ipsec.ike.message.IkePayload;
38 
39 import java.lang.annotation.Retention;
40 import java.lang.annotation.RetentionPolicy;
41 import java.net.Inet4Address;
42 import java.net.Inet6Address;
43 import java.net.InetAddress;
44 import java.security.PrivateKey;
45 import java.security.cert.TrustAnchor;
46 import java.security.cert.X509Certificate;
47 import java.security.interfaces.RSAPrivateKey;
48 import java.util.ArrayList;
49 import java.util.Arrays;
50 import java.util.Collections;
51 import java.util.LinkedList;
52 import java.util.List;
53 import java.util.Objects;
54 import java.util.concurrent.TimeUnit;
55 
56 /**
57  * IkeSessionParams contains all user provided configurations for negotiating an {@link IkeSession}.
58  *
59  * <p>Note that all negotiated configurations will be reused during rekey including SA Proposal and
60  * lifetime.
61  *
62  * @hide
63  */
64 @SystemApi
65 public final class IkeSessionParams {
66     /** @hide */
67     @Retention(RetentionPolicy.SOURCE)
68     @IntDef({IKE_AUTH_METHOD_PSK, IKE_AUTH_METHOD_PUB_KEY_SIGNATURE, IKE_AUTH_METHOD_EAP})
69     public @interface IkeAuthMethod {}
70 
71     // Constants to describe user configured authentication methods.
72     /** @hide */
73     public static final int IKE_AUTH_METHOD_PSK = 1;
74     /** @hide */
75     public static final int IKE_AUTH_METHOD_PUB_KEY_SIGNATURE = 2;
76     /** @hide */
77     public static final int IKE_AUTH_METHOD_EAP = 3;
78 
79     /** @hide */
80     @Retention(RetentionPolicy.SOURCE)
81     @IntDef({IKE_OPTION_ACCEPT_ANY_REMOTE_ID, IKE_OPTION_EAP_ONLY_AUTH})
82     public @interface IkeOption {}
83 
84     /**
85      * If set, the IKE library will accept any remote (server) identity, even if it does not match
86      * the configured remote identity
87      *
88      * <p>See {@link Builder#setRemoteIdentification(IkeIdentification)}
89      */
90     public static final int IKE_OPTION_ACCEPT_ANY_REMOTE_ID = 0;
91     /**
92      * If set, and EAP has been configured as the authentication method, the IKE library will
93      * request that the remote (also) use an EAP-only authentication flow.
94      *
95      * <p>@see {@link Builder#setAuthEap(X509Certificate, EapSessionConfig)}
96      */
97     public static final int IKE_OPTION_EAP_ONLY_AUTH = 1;
98 
99     private static final int MIN_IKE_OPTION = IKE_OPTION_ACCEPT_ANY_REMOTE_ID;
100     private static final int MAX_IKE_OPTION = IKE_OPTION_EAP_ONLY_AUTH;
101 
102     /** @hide */
103     @VisibleForTesting static final int IKE_HARD_LIFETIME_SEC_MINIMUM = 300; // 5 minutes
104     /** @hide */
105     @VisibleForTesting static final int IKE_HARD_LIFETIME_SEC_MAXIMUM = 86400; // 24 hours
106     /** @hide */
107     @VisibleForTesting static final int IKE_HARD_LIFETIME_SEC_DEFAULT = 14400; // 4 hours
108 
109     /** @hide */
110     @VisibleForTesting static final int IKE_SOFT_LIFETIME_SEC_MINIMUM = 120; // 2 minutes
111     /** @hide */
112     @VisibleForTesting static final int IKE_SOFT_LIFETIME_SEC_DEFAULT = 7200; // 2 hours
113 
114     /** @hide */
115     @VisibleForTesting
116     static final int IKE_LIFETIME_MARGIN_SEC_MINIMUM = (int) TimeUnit.MINUTES.toSeconds(1L);
117 
118     /** @hide */
119     @VisibleForTesting static final int IKE_DPD_DELAY_SEC_MIN = 20;
120     /** @hide */
121     @VisibleForTesting static final int IKE_DPD_DELAY_SEC_MAX = 1800; // 30 minutes
122     /** @hide */
123     @VisibleForTesting static final int IKE_DPD_DELAY_SEC_DEFAULT = 120; // 2 minutes
124 
125     /** @hide */
126     @VisibleForTesting static final int IKE_RETRANS_TIMEOUT_MS_MIN = 500;
127     /** @hide */
128     @VisibleForTesting
129     static final int IKE_RETRANS_TIMEOUT_MS_MAX = (int) TimeUnit.MINUTES.toMillis(30L);
130     /** @hide */
131     @VisibleForTesting static final int IKE_RETRANS_MAX_ATTEMPTS_MAX = 10;
132     /** @hide */
133     @VisibleForTesting
134     static final int[] IKE_RETRANS_TIMEOUT_MS_LIST_DEFAULT =
135             new int[] {500, 1000, 2000, 4000, 8000};
136 
137     @NonNull private final String mServerHostname;
138     @NonNull private final Network mNetwork;
139 
140     @NonNull private final IkeSaProposal[] mSaProposals;
141 
142     @NonNull private final IkeIdentification mLocalIdentification;
143     @NonNull private final IkeIdentification mRemoteIdentification;
144 
145     @NonNull private final IkeAuthConfig mLocalAuthConfig;
146     @NonNull private final IkeAuthConfig mRemoteAuthConfig;
147 
148     @NonNull private final IkeConfigAttribute[] mConfigRequests;
149 
150     @NonNull private final int[] mRetransTimeoutMsList;
151 
152     private final long mIkeOptions;
153 
154     private final int mHardLifetimeSec;
155     private final int mSoftLifetimeSec;
156 
157     private final int mDpdDelaySec;
158 
159     private final boolean mIsIkeFragmentationSupported;
160 
IkeSessionParams( @onNull String serverHostname, @NonNull Network network, @NonNull IkeSaProposal[] proposals, @NonNull IkeIdentification localIdentification, @NonNull IkeIdentification remoteIdentification, @NonNull IkeAuthConfig localAuthConfig, @NonNull IkeAuthConfig remoteAuthConfig, @NonNull IkeConfigAttribute[] configRequests, @NonNull int[] retransTimeoutMsList, long ikeOptions, int hardLifetimeSec, int softLifetimeSec, int dpdDelaySec, boolean isIkeFragmentationSupported)161     private IkeSessionParams(
162             @NonNull String serverHostname,
163             @NonNull Network network,
164             @NonNull IkeSaProposal[] proposals,
165             @NonNull IkeIdentification localIdentification,
166             @NonNull IkeIdentification remoteIdentification,
167             @NonNull IkeAuthConfig localAuthConfig,
168             @NonNull IkeAuthConfig remoteAuthConfig,
169             @NonNull IkeConfigAttribute[] configRequests,
170             @NonNull int[] retransTimeoutMsList,
171             long ikeOptions,
172             int hardLifetimeSec,
173             int softLifetimeSec,
174             int dpdDelaySec,
175             boolean isIkeFragmentationSupported) {
176         mServerHostname = serverHostname;
177         mNetwork = network;
178 
179         mSaProposals = proposals;
180 
181         mLocalIdentification = localIdentification;
182         mRemoteIdentification = remoteIdentification;
183 
184         mLocalAuthConfig = localAuthConfig;
185         mRemoteAuthConfig = remoteAuthConfig;
186 
187         mConfigRequests = configRequests;
188 
189         mRetransTimeoutMsList = retransTimeoutMsList;
190 
191         mIkeOptions = ikeOptions;
192 
193         mHardLifetimeSec = hardLifetimeSec;
194         mSoftLifetimeSec = softLifetimeSec;
195 
196         mDpdDelaySec = dpdDelaySec;
197 
198         mIsIkeFragmentationSupported = isIkeFragmentationSupported;
199     }
200 
validateIkeOptionOrThrow(@keOption int ikeOption)201     private static void validateIkeOptionOrThrow(@IkeOption int ikeOption) {
202         if (ikeOption < MIN_IKE_OPTION || ikeOption > MAX_IKE_OPTION) {
203             throw new IllegalArgumentException("Invalid IKE Option: " + ikeOption);
204         }
205     }
206 
getOptionBitValue(int ikeOption)207     private static long getOptionBitValue(int ikeOption) {
208         return 1 << ikeOption;
209     }
210 
211     /**
212      * Retrieves the configured server hostname
213      *
214      * <p>The configured server hostname will be resolved during IKE Session creation.
215      */
216     @NonNull
getServerHostname()217     public String getServerHostname() {
218         return mServerHostname;
219     }
220 
221     /** Retrieves the configured {@link Network} */
222     @NonNull
getNetwork()223     public Network getNetwork() {
224         return mNetwork;
225     }
226 
227     /** Retrieves all ChildSaProposals configured */
228     @NonNull
getSaProposals()229     public List<IkeSaProposal> getSaProposals() {
230         return Arrays.asList(mSaProposals);
231     }
232 
233     /** @hide */
getSaProposalsInternal()234     public IkeSaProposal[] getSaProposalsInternal() {
235         return mSaProposals;
236     }
237 
238     /** Retrieves the local (client) identity */
239     @NonNull
getLocalIdentification()240     public IkeIdentification getLocalIdentification() {
241         return mLocalIdentification;
242     }
243 
244     /** Retrieves the required remote (server) identity */
245     @NonNull
getRemoteIdentification()246     public IkeIdentification getRemoteIdentification() {
247         return mRemoteIdentification;
248     }
249 
250     /** Retrieves the local (client) authentication configuration */
251     @NonNull
getLocalAuthConfig()252     public IkeAuthConfig getLocalAuthConfig() {
253         return mLocalAuthConfig;
254     }
255 
256     /** Retrieves the remote (server) authentication configuration */
257     @NonNull
getRemoteAuthConfig()258     public IkeAuthConfig getRemoteAuthConfig() {
259         return mRemoteAuthConfig;
260     }
261 
262     /** Retrieves hard lifetime in seconds */
263     // Use "second" because smaller unit won't make sense to describe a rekey interval.
264     @SuppressLint("MethodNameUnits")
265     @IntRange(from = IKE_HARD_LIFETIME_SEC_MINIMUM, to = IKE_HARD_LIFETIME_SEC_MAXIMUM)
getHardLifetimeSeconds()266     public int getHardLifetimeSeconds() {
267         return mHardLifetimeSec;
268     }
269 
270     /** Retrieves soft lifetime in seconds */
271     // Use "second" because smaller unit does not make sense to a rekey interval.
272     @SuppressLint("MethodNameUnits")
273     @IntRange(from = IKE_SOFT_LIFETIME_SEC_MINIMUM, to = IKE_HARD_LIFETIME_SEC_MAXIMUM)
getSoftLifetimeSeconds()274     public int getSoftLifetimeSeconds() {
275         return mSoftLifetimeSec;
276     }
277 
278     /** Retrieves the Dead Peer Detection(DPD) delay in seconds */
279     @IntRange(from = IKE_DPD_DELAY_SEC_MIN, to = IKE_DPD_DELAY_SEC_MAX)
getDpdDelaySeconds()280     public int getDpdDelaySeconds() {
281         return mDpdDelaySec;
282     }
283 
284     /**
285      * Retrieves the relative retransmission timeout list in milliseconds
286      *
287      * <p>@see {@link Builder#setRetransmissionTimeoutsMillis(int[])}
288      */
getRetransmissionTimeoutsMillis()289     public int[] getRetransmissionTimeoutsMillis() {
290         return mRetransTimeoutMsList;
291     }
292 
293     /** Checks if the given IKE Session negotiation option is set */
hasIkeOption(@keOption int ikeOption)294     public boolean hasIkeOption(@IkeOption int ikeOption) {
295         validateIkeOptionOrThrow(ikeOption);
296         return (mIkeOptions & getOptionBitValue(ikeOption)) != 0;
297     }
298 
299     /** @hide */
getHardLifetimeMsInternal()300     public long getHardLifetimeMsInternal() {
301         return TimeUnit.SECONDS.toMillis((long) mHardLifetimeSec);
302     }
303 
304     /** @hide */
getSoftLifetimeMsInternal()305     public long getSoftLifetimeMsInternal() {
306         return TimeUnit.SECONDS.toMillis((long) mSoftLifetimeSec);
307     }
308 
309     /** @hide */
isIkeFragmentationSupported()310     public boolean isIkeFragmentationSupported() {
311         return mIsIkeFragmentationSupported;
312     }
313 
314     /** @hide */
getConfigurationAttributesInternal()315     public IkeConfigAttribute[] getConfigurationAttributesInternal() {
316         return mConfigRequests;
317     }
318 
319     /** Retrieves the list of Configuration Requests */
320     @NonNull
getConfigurationRequests()321     public List<IkeConfigRequest> getConfigurationRequests() {
322         return Collections.unmodifiableList(Arrays.asList(mConfigRequests));
323     }
324 
325     /** Represents an IKE session configuration request type */
326     public interface IkeConfigRequest {}
327 
328     /** Represents an IPv4 P_CSCF request */
329     public interface ConfigRequestIpv4PcscfServer extends IkeConfigRequest {
330         /**
331          * Retrieves the requested IPv4 P_CSCF server address
332          *
333          * @return The requested P_CSCF server address, or null if no specific P_CSCF server was
334          *     requested
335          */
336         @Nullable
getAddress()337         Inet4Address getAddress();
338     }
339 
340     /** Represents an IPv6 P_CSCF request */
341     public interface ConfigRequestIpv6PcscfServer extends IkeConfigRequest {
342         /**
343          * Retrieves the requested IPv6 P_CSCF server address
344          *
345          * @return The requested P_CSCF server address, or null if no specific P_CSCF server was
346          *     requested
347          */
348         @Nullable
getAddress()349         Inet6Address getAddress();
350     }
351 
352     /** This class contains common information of an IKEv2 authentication configuration. */
353     public abstract static class IkeAuthConfig {
354         /** @hide */
355         @IkeAuthMethod public final int mAuthMethod;
356 
357         /** @hide */
IkeAuthConfig(@keAuthMethod int authMethod)358         IkeAuthConfig(@IkeAuthMethod int authMethod) {
359             mAuthMethod = authMethod;
360         }
361     }
362 
363     /**
364      * This class represents the configuration to support IKEv2 pre-shared-key-based authentication
365      * of local or remote side.
366      */
367     public static class IkeAuthPskConfig extends IkeAuthConfig {
368         /** @hide */
369         @NonNull public final byte[] mPsk;
370 
IkeAuthPskConfig(byte[] psk)371         private IkeAuthPskConfig(byte[] psk) {
372             super(IKE_AUTH_METHOD_PSK);
373             mPsk = psk;
374         }
375 
376         /** Retrieves the pre-shared key */
377         @NonNull
getPsk()378         public byte[] getPsk() {
379             return Arrays.copyOf(mPsk, mPsk.length);
380         }
381     }
382 
383     /**
384      * This class represents the configuration to support IKEv2 public-key-signature-based
385      * authentication of the remote side.
386      */
387     public static class IkeAuthDigitalSignRemoteConfig extends IkeAuthConfig {
388         /** @hide */
389         @Nullable public final TrustAnchor mTrustAnchor;
390 
391         /**
392          * If a certificate is provided, it MUST be the root CA used by the remote (server), or
393          * authentication will fail. If no certificate is provided, any root CA in the system's
394          * truststore is considered acceptable.
395          */
IkeAuthDigitalSignRemoteConfig(@ullable X509Certificate caCert)396         private IkeAuthDigitalSignRemoteConfig(@Nullable X509Certificate caCert) {
397             super(IKE_AUTH_METHOD_PUB_KEY_SIGNATURE);
398             if (caCert == null) {
399                 mTrustAnchor = null;
400             } else {
401                 // The name constraints extension, defined in RFC 5280, indicates a name space
402                 // within which all subject names in subsequent certificates in a certification path
403                 // MUST be located.
404                 mTrustAnchor = new TrustAnchor(caCert, null /*nameConstraints*/);
405 
406                 // TODO: Investigate if we need to support the name constraints extension.
407             }
408         }
409 
410         /** Retrieves the provided CA certificate for validating the remote certificate(s) */
411         @Nullable
getRemoteCaCert()412         public X509Certificate getRemoteCaCert() {
413             if (mTrustAnchor == null) return null;
414             return mTrustAnchor.getTrustedCert();
415         }
416     }
417 
418     /**
419      * This class represents the configuration to support IKEv2 public-key-signature-based
420      * authentication of the local side.
421      */
422     public static class IkeAuthDigitalSignLocalConfig extends IkeAuthConfig {
423         /** @hide */
424         @NonNull public final X509Certificate mEndCert;
425 
426         /** @hide */
427         @NonNull public final List<X509Certificate> mIntermediateCerts;
428 
429         /** @hide */
430         @NonNull public final PrivateKey mPrivateKey;
431 
IkeAuthDigitalSignLocalConfig( @onNull X509Certificate clientEndCert, @NonNull List<X509Certificate> clientIntermediateCerts, @NonNull PrivateKey privateKey)432         private IkeAuthDigitalSignLocalConfig(
433                 @NonNull X509Certificate clientEndCert,
434                 @NonNull List<X509Certificate> clientIntermediateCerts,
435                 @NonNull PrivateKey privateKey) {
436             super(IKE_AUTH_METHOD_PUB_KEY_SIGNATURE);
437             mEndCert = clientEndCert;
438             mIntermediateCerts = clientIntermediateCerts;
439             mPrivateKey = privateKey;
440         }
441 
442         /** Retrieves the client end certificate */
443         @NonNull
getClientEndCertificate()444         public X509Certificate getClientEndCertificate() {
445             return mEndCert;
446         }
447 
448         /** Retrieves the intermediate certificates */
449         @NonNull
getIntermediateCertificates()450         public List<X509Certificate> getIntermediateCertificates() {
451             return mIntermediateCerts;
452         }
453 
454         /** Retrieves the private key */
455         @NonNull
getPrivateKey()456         public PrivateKey getPrivateKey() {
457             return mPrivateKey;
458         }
459     }
460 
461     /**
462      * This class represents the configuration to support EAP authentication of the local side.
463      *
464      * <p>@see {@link IkeSessionParams.Builder#setAuthEap(X509Certificate, EapSessionConfig)}
465      */
466     public static class IkeAuthEapConfig extends IkeAuthConfig {
467         /** @hide */
468         @NonNull public final EapSessionConfig mEapConfig;
469 
IkeAuthEapConfig(EapSessionConfig eapConfig)470         private IkeAuthEapConfig(EapSessionConfig eapConfig) {
471             super(IKE_AUTH_METHOD_EAP);
472 
473             mEapConfig = eapConfig;
474         }
475 
476         /** Retrieves EAP configuration */
477         @NonNull
getEapConfig()478         public EapSessionConfig getEapConfig() {
479             return mEapConfig;
480         }
481     }
482 
483     /** This class can be used to incrementally construct a {@link IkeSessionParams}. */
484     public static final class Builder {
485         @NonNull private final ConnectivityManager mConnectivityManager;
486 
487         @NonNull private final List<IkeSaProposal> mSaProposalList = new LinkedList<>();
488         @NonNull private final List<IkeConfigAttribute> mConfigRequestList = new ArrayList<>();
489 
490         @NonNull
491         private int[] mRetransTimeoutMsList =
492                 Arrays.copyOf(
493                         IKE_RETRANS_TIMEOUT_MS_LIST_DEFAULT,
494                         IKE_RETRANS_TIMEOUT_MS_LIST_DEFAULT.length);
495 
496         @NonNull private String mServerHostname;
497         @Nullable private Network mNetwork;
498 
499         @Nullable private IkeIdentification mLocalIdentification;
500         @Nullable private IkeIdentification mRemoteIdentification;
501 
502         @Nullable private IkeAuthConfig mLocalAuthConfig;
503         @Nullable private IkeAuthConfig mRemoteAuthConfig;
504 
505         private long mIkeOptions = 0;
506 
507         private int mHardLifetimeSec = IKE_HARD_LIFETIME_SEC_DEFAULT;
508         private int mSoftLifetimeSec = IKE_SOFT_LIFETIME_SEC_DEFAULT;
509 
510         private int mDpdDelaySec = IKE_DPD_DELAY_SEC_DEFAULT;
511 
512         private boolean mIsIkeFragmentationSupported = false;
513 
514         /**
515          * Construct Builder
516          *
517          * @param context a valid {@link Context} instance.
518          */
Builder(@onNull Context context)519         public Builder(@NonNull Context context) {
520             this((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE));
521         }
522 
523         /** @hide */
524         @VisibleForTesting
Builder(ConnectivityManager connectManager)525         public Builder(ConnectivityManager connectManager) {
526             mConnectivityManager = connectManager;
527         }
528 
529         /**
530          * Sets the server hostname for the {@link IkeSessionParams} being built.
531          *
532          * @param serverHostname the hostname of the IKE server, such as "ike.android.com".
533          * @return Builder this, to facilitate chaining.
534          */
535         @NonNull
setServerHostname(@onNull String serverHostname)536         public Builder setServerHostname(@NonNull String serverHostname) {
537             Objects.requireNonNull(serverHostname, "Required argument not provided");
538 
539             mServerHostname = serverHostname;
540             return this;
541         }
542 
543         /**
544          * Sets the {@link Network} for the {@link IkeSessionParams} being built.
545          *
546          * <p>If no {@link Network} is provided, the default Network (as per {@link
547          * ConnectivityManager#getActiveNetwork()}) will be used.
548          *
549          * @param network the {@link Network} that IKE Session will use.
550          * @return Builder this, to facilitate chaining.
551          */
552         @NonNull
setNetwork(@onNull Network network)553         public Builder setNetwork(@NonNull Network network) {
554             if (network == null) {
555                 throw new NullPointerException("Required argument not provided");
556             }
557 
558             mNetwork = network;
559             return this;
560         }
561 
562         /**
563          * Sets local IKE identification for the {@link IkeSessionParams} being built.
564          *
565          * <p>It is not allowed to use KEY ID together with digital-signature-based authentication
566          * as per RFC 7296.
567          *
568          * @param identification the local IKE identification.
569          * @return Builder this, to facilitate chaining.
570          */
571         @NonNull
setLocalIdentification(@onNull IkeIdentification identification)572         public Builder setLocalIdentification(@NonNull IkeIdentification identification) {
573             if (identification == null) {
574                 throw new NullPointerException("Required argument not provided");
575             }
576 
577             mLocalIdentification = identification;
578             return this;
579         }
580 
581         /**
582          * Sets remote IKE identification for the {@link IkeSessionParams} being built.
583          *
584          * @param identification the remote IKE identification.
585          * @return Builder this, to facilitate chaining.
586          */
587         @NonNull
setRemoteIdentification(@onNull IkeIdentification identification)588         public Builder setRemoteIdentification(@NonNull IkeIdentification identification) {
589             if (identification == null) {
590                 throw new NullPointerException("Required argument not provided");
591             }
592 
593             mRemoteIdentification = identification;
594             return this;
595         }
596 
597         /**
598          * Adds an IKE SA proposal to the {@link IkeSessionParams} being built.
599          *
600          * @param proposal IKE SA proposal.
601          * @return Builder this, to facilitate chaining.
602          */
603         @NonNull
addSaProposal(@onNull IkeSaProposal proposal)604         public Builder addSaProposal(@NonNull IkeSaProposal proposal) {
605             if (proposal == null) {
606                 throw new NullPointerException("Required argument not provided");
607             }
608 
609             if (proposal.getProtocolId() != IkePayload.PROTOCOL_ID_IKE) {
610                 throw new IllegalArgumentException(
611                         "Expected IKE SA Proposal but received Child SA proposal");
612             }
613             mSaProposalList.add(proposal);
614             return this;
615         }
616 
617         /**
618          * Configures the {@link IkeSession} to use pre-shared-key-based authentication.
619          *
620          * <p>Both client and server MUST be authenticated using the provided shared key. IKE
621          * authentication will fail if the remote peer tries to use other authentication methods.
622          *
623          * <p>Callers MUST declare only one authentication method. Calling this function will
624          * override the previously set authentication configuration.
625          *
626          * <p>Callers SHOULD NOT use this if any other authentication methods can be used; PSK-based
627          * authentication is generally considered insecure.
628          *
629          * @param sharedKey the shared key.
630          * @return Builder this, to facilitate chaining.
631          */
632         @NonNull
setAuthPsk(@onNull byte[] sharedKey)633         public Builder setAuthPsk(@NonNull byte[] sharedKey) {
634             if (sharedKey == null) {
635                 throw new NullPointerException("Required argument not provided");
636             }
637 
638             mLocalAuthConfig = new IkeAuthPskConfig(sharedKey);
639             mRemoteAuthConfig = new IkeAuthPskConfig(sharedKey);
640             return this;
641         }
642 
643         /**
644          * Configures the {@link IkeSession} to use EAP authentication.
645          *
646          * <p>Not all EAP methods provide mutual authentication. As such EAP MUST be used in
647          * conjunction with a public-key-signature-based authentication of the remote server, unless
648          * EAP-Only authentication is enabled.
649          *
650          * <p>Callers may enable EAP-Only authentication by setting {@link
651          * IKE_OPTION_EAP_ONLY_AUTH}, which will make IKE library request the remote to use EAP-Only
652          * authentication. The remote may opt to reject the request, at which point the received
653          * certificates and authentication payload WILL be validated with the provided root CA or
654          * system's truststore as usual. Only safe EAP methods as listed in RFC 5998 will be
655          * accepted for EAP-Only authentication.
656          *
657          * <p>If {@link IKE_OPTION_EAP_ONLY_AUTH} is set, callers MUST configure EAP as the
658          * authentication method and all EAP methods set in EAP Session configuration MUST be safe
659          * methods that are accepted for EAP-Only authentication. Otherwise callers will get an
660          * exception when building the {@link IkeSessionParams}
661          *
662          * <p>Callers MUST declare only one authentication method. Calling this function will
663          * override the previously set authentication configuration.
664          *
665          * @see <a href="https://tools.ietf.org/html/rfc5280">RFC 5280, Internet X.509 Public Key
666          *     Infrastructure Certificate and Certificate Revocation List (CRL) Profile</a>
667          * @see <a href="https://tools.ietf.org/html/rfc5998">RFC 5998, An Extension for EAP-Only
668          *     Authentication in IKEv2
669          * @param serverCaCert the CA certificate for validating the received server certificate(s).
670          *     If a certificate is provided, it MUST be the root CA used by the server, or
671          *     authentication will fail. If no certificate is provided, any root CA in the system's
672          *     truststore is considered acceptable.
673          * @return Builder this, to facilitate chaining.
674          */
675         // TODO(b/151667921): Consider also supporting configuring EAP method that is not accepted
676         // by EAP-Only when {@link IKE_OPTION_EAP_ONLY_AUTH} is set
677         @NonNull
setAuthEap( @ullable X509Certificate serverCaCert, @NonNull EapSessionConfig eapConfig)678         public Builder setAuthEap(
679                 @Nullable X509Certificate serverCaCert, @NonNull EapSessionConfig eapConfig) {
680             if (eapConfig == null) {
681                 throw new NullPointerException("Required argument not provided");
682             }
683 
684             mLocalAuthConfig = new IkeAuthEapConfig(eapConfig);
685             mRemoteAuthConfig = new IkeAuthDigitalSignRemoteConfig(serverCaCert);
686 
687             return this;
688         }
689 
690         /**
691          * Configures the {@link IkeSession} to use public-key-signature-based authentication.
692          *
693          * <p>The public key included by the client end certificate and the private key used for
694          * signing MUST be a matching key pair.
695          *
696          * <p>The IKE library will use the strongest signature algorithm supported by both sides.
697          *
698          * <p>Currenly only RSA digital signature is supported.
699          *
700          * @param serverCaCert the CA certificate for validating the received server certificate(s).
701          *     If a certificate is provided, it MUST be the root CA used by the server, or
702          *     authentication will fail. If no certificate is provided, any root CA in the system's
703          *     truststore is considered acceptable.
704          * @param clientEndCert the end certificate for remote server to verify the locally
705          *     generated signature.
706          * @param clientPrivateKey private key to generate outbound digital signature. Only {@link
707          *     RSAPrivateKey} is supported.
708          * @return Builder this, to facilitate chaining.
709          */
710         @NonNull
setAuthDigitalSignature( @ullable X509Certificate serverCaCert, @NonNull X509Certificate clientEndCert, @NonNull PrivateKey clientPrivateKey)711         public Builder setAuthDigitalSignature(
712                 @Nullable X509Certificate serverCaCert,
713                 @NonNull X509Certificate clientEndCert,
714                 @NonNull PrivateKey clientPrivateKey) {
715             return setAuthDigitalSignature(
716                     serverCaCert,
717                     clientEndCert,
718                     new LinkedList<X509Certificate>(),
719                     clientPrivateKey);
720         }
721 
722         /**
723          * Configures the {@link IkeSession} to use public-key-signature-based authentication.
724          *
725          * <p>The public key included by the client end certificate and the private key used for
726          * signing MUST be a matching key pair.
727          *
728          * <p>The IKE library will use the strongest signature algorithm supported by both sides.
729          *
730          * <p>Currenly only RSA digital signature is supported.
731          *
732          * @param serverCaCert the CA certificate for validating the received server certificate(s).
733          *     If a null value is provided, IKE library will try all default CA certificates stored
734          *     in Android system to do the validation. Otherwise, it will only use the provided CA
735          *     certificate.
736          * @param clientEndCert the end certificate for remote server to verify locally generated
737          *     signature.
738          * @param clientIntermediateCerts intermediate certificates for the remote server to
739          *     validate the end certificate.
740          * @param clientPrivateKey private key to generate outbound digital signature. Only {@link
741          *     RSAPrivateKey} is supported.
742          * @return Builder this, to facilitate chaining.
743          */
744         @NonNull
setAuthDigitalSignature( @ullable X509Certificate serverCaCert, @NonNull X509Certificate clientEndCert, @NonNull List<X509Certificate> clientIntermediateCerts, @NonNull PrivateKey clientPrivateKey)745         public Builder setAuthDigitalSignature(
746                 @Nullable X509Certificate serverCaCert,
747                 @NonNull X509Certificate clientEndCert,
748                 @NonNull List<X509Certificate> clientIntermediateCerts,
749                 @NonNull PrivateKey clientPrivateKey) {
750             if (clientEndCert == null
751                     || clientIntermediateCerts == null
752                     || clientPrivateKey == null) {
753                 throw new NullPointerException("Required argument not provided");
754             }
755 
756             if (!(clientPrivateKey instanceof RSAPrivateKey)) {
757                 throw new IllegalArgumentException("Unsupported private key type");
758             }
759 
760             mLocalAuthConfig =
761                     new IkeAuthDigitalSignLocalConfig(
762                             clientEndCert, clientIntermediateCerts, clientPrivateKey);
763             mRemoteAuthConfig = new IkeAuthDigitalSignRemoteConfig(serverCaCert);
764 
765             return this;
766         }
767 
768         /**
769          * Adds a specific internal P_CSCF server request to the {@link IkeSessionParams} being
770          * built.
771          *
772          * @param address the requested P_CSCF address.
773          * @return Builder this, to facilitate chaining.
774          */
775         @NonNull
addPcscfServerRequest(@onNull InetAddress address)776         public Builder addPcscfServerRequest(@NonNull InetAddress address) {
777             if (address == null) {
778                 throw new NullPointerException("Required argument not provided");
779             }
780 
781             if (address instanceof Inet4Address) {
782                 mConfigRequestList.add(new ConfigAttributeIpv4Pcscf((Inet4Address) address));
783             } else if (address instanceof Inet6Address) {
784                 mConfigRequestList.add(new ConfigAttributeIpv6Pcscf((Inet6Address) address));
785             } else {
786                 throw new IllegalArgumentException("Invalid address family");
787             }
788             return this;
789         }
790 
791         /**
792          * Adds a internal P_CSCF server request to the {@link IkeSessionParams} being built.
793          *
794          * @param addressFamily the address family. Only {@link OsConstants.AF_INET} and {@link
795          *     OsConstants.AF_INET6} are allowed.
796          * @return Builder this, to facilitate chaining.
797          */
798         @NonNull
addPcscfServerRequest(int addressFamily)799         public Builder addPcscfServerRequest(int addressFamily) {
800             if (addressFamily == AF_INET) {
801                 mConfigRequestList.add(new ConfigAttributeIpv4Pcscf());
802                 return this;
803             } else if (addressFamily == AF_INET6) {
804                 mConfigRequestList.add(new ConfigAttributeIpv6Pcscf());
805                 return this;
806             } else {
807                 throw new IllegalArgumentException("Invalid address family: " + addressFamily);
808             }
809         }
810 
811         /**
812          * Sets hard and soft lifetimes.
813          *
814          * <p>Lifetimes will not be negotiated with the remote IKE server.
815          *
816          * @param hardLifetimeSeconds number of seconds after which IKE SA will expire. Defaults to
817          *     14400 seconds (4 hours). MUST be a value from 300 seconds (5 minutes) to 86400
818          *     seconds (24 hours), inclusive.
819          * @param softLifetimeSeconds number of seconds after which IKE SA will request rekey.
820          *     Defaults to 7200 seconds (2 hours). MUST be at least 120 seconds (2 minutes), and at
821          *     least 60 seconds (1 minute) shorter than the hard lifetime.
822          * @return Builder this, to facilitate chaining.
823          */
824         @NonNull
setLifetimeSeconds( @ntRangefrom = IKE_HARD_LIFETIME_SEC_MINIMUM, to = IKE_HARD_LIFETIME_SEC_MAXIMUM) int hardLifetimeSeconds, @IntRange(from = IKE_SOFT_LIFETIME_SEC_MINIMUM, to = IKE_HARD_LIFETIME_SEC_MAXIMUM) int softLifetimeSeconds)825         public Builder setLifetimeSeconds(
826                 @IntRange(from = IKE_HARD_LIFETIME_SEC_MINIMUM, to = IKE_HARD_LIFETIME_SEC_MAXIMUM)
827                         int hardLifetimeSeconds,
828                 @IntRange(from = IKE_SOFT_LIFETIME_SEC_MINIMUM, to = IKE_HARD_LIFETIME_SEC_MAXIMUM)
829                         int softLifetimeSeconds) {
830             if (hardLifetimeSeconds < IKE_HARD_LIFETIME_SEC_MINIMUM
831                     || hardLifetimeSeconds > IKE_HARD_LIFETIME_SEC_MAXIMUM
832                     || softLifetimeSeconds < IKE_SOFT_LIFETIME_SEC_MINIMUM
833                     || hardLifetimeSeconds - softLifetimeSeconds
834                             < IKE_LIFETIME_MARGIN_SEC_MINIMUM) {
835                 throw new IllegalArgumentException("Invalid lifetime value");
836             }
837 
838             mHardLifetimeSec = hardLifetimeSeconds;
839             mSoftLifetimeSec = softLifetimeSeconds;
840             return this;
841         }
842 
843         /**
844          * Sets the Dead Peer Detection(DPD) delay in seconds.
845          *
846          * @param dpdDelaySeconds number of seconds after which IKE SA will initiate DPD if no
847          *     inbound cryptographically protected IKE message was received. Defaults to 120
848          *     seconds. MUST be a value from 20 seconds to 1800 seconds, inclusive.
849          * @return Builder this, to facilitate chaining.
850          */
851         @NonNull
setDpdDelaySeconds( @ntRangefrom = IKE_DPD_DELAY_SEC_MIN, to = IKE_DPD_DELAY_SEC_MAX) int dpdDelaySeconds)852         public Builder setDpdDelaySeconds(
853                 @IntRange(from = IKE_DPD_DELAY_SEC_MIN, to = IKE_DPD_DELAY_SEC_MAX)
854                         int dpdDelaySeconds) {
855             if (dpdDelaySeconds < IKE_DPD_DELAY_SEC_MIN
856                     || dpdDelaySeconds > IKE_DPD_DELAY_SEC_MAX) {
857                 throw new IllegalArgumentException("Invalid DPD delay value");
858             }
859             mDpdDelaySec = dpdDelaySeconds;
860             return this;
861         }
862 
863         /**
864          * Sets the retransmission timeout list in milliseconds.
865          *
866          * <p>Configures the retransmission by providing an array of relative retransmission
867          * timeouts in milliseconds, where each timeout is the waiting time before next retry,
868          * except the last timeout is the waiting time before terminating the IKE Session. Each
869          * element in the array MUST be a value from 500 ms to 1800000 ms (30 minutes). The length
870          * of the array MUST NOT exceed 10. This retransmission timeout list defaults to {0.5s, 1s,
871          * 2s, 4s, 8s}
872          *
873          * @param retransTimeoutMillisList the array of relative retransmission timeout in
874          *     milliseconds.
875          * @return Builder this, to facilitate chaining.
876          */
877         @NonNull
setRetransmissionTimeoutsMillis(@onNull int[] retransTimeoutMillisList)878         public Builder setRetransmissionTimeoutsMillis(@NonNull int[] retransTimeoutMillisList) {
879             boolean isValid = true;
880             if (retransTimeoutMillisList == null
881                     || retransTimeoutMillisList.length == 0
882                     || retransTimeoutMillisList.length > IKE_RETRANS_MAX_ATTEMPTS_MAX) {
883                 isValid = false;
884             }
885             for (int t : retransTimeoutMillisList) {
886                 if (t < IKE_RETRANS_TIMEOUT_MS_MIN || t > IKE_RETRANS_TIMEOUT_MS_MAX) {
887                     isValid = false;
888                 }
889             }
890             if (!isValid) throw new IllegalArgumentException("Invalid retransmission timeout list");
891 
892             mRetransTimeoutMsList = retransTimeoutMillisList;
893             return this;
894         }
895 
896         /**
897          * Sets the specified IKE Option as enabled.
898          *
899          * @param ikeOption the option to be enabled.
900          * @return Builder this, to facilitate chaining.
901          */
902         @NonNull
addIkeOption(@keOption int ikeOption)903         public Builder addIkeOption(@IkeOption int ikeOption) {
904             validateIkeOptionOrThrow(ikeOption);
905             mIkeOptions |= getOptionBitValue(ikeOption);
906             return this;
907         }
908 
909         /**
910          * Resets (disables) the specified IKE Option.
911          *
912          * @param ikeOption the option to be disabled.
913          * @return Builder this, to facilitate chaining.
914          */
915         @NonNull
removeIkeOption(@keOption int ikeOption)916         public Builder removeIkeOption(@IkeOption int ikeOption) {
917             validateIkeOptionOrThrow(ikeOption);
918             mIkeOptions &= ~getOptionBitValue(ikeOption);
919             return this;
920         }
921 
922         /**
923          * Validates and builds the {@link IkeSessionParams}.
924          *
925          * @return IkeSessionParams the validated IkeSessionParams.
926          */
927         @NonNull
build()928         public IkeSessionParams build() {
929             if (mSaProposalList.isEmpty()) {
930                 throw new IllegalArgumentException("IKE SA proposal not found");
931             }
932 
933             Network network = mNetwork != null ? mNetwork : mConnectivityManager.getActiveNetwork();
934             if (network == null) {
935                 throw new IllegalArgumentException("Network not found");
936             }
937 
938             if (mServerHostname == null
939                     || mLocalIdentification == null
940                     || mRemoteIdentification == null
941                     || mLocalAuthConfig == null
942                     || mRemoteAuthConfig == null) {
943                 throw new IllegalArgumentException("Necessary parameter missing.");
944             }
945 
946             if ((mIkeOptions & getOptionBitValue(IKE_OPTION_EAP_ONLY_AUTH)) != 0) {
947                 if (!(mLocalAuthConfig instanceof IkeAuthEapConfig)) {
948                     throw new IllegalArgumentException(
949                             "If IKE_OPTION_EAP_ONLY_AUTH is set,"
950                                     + " eap authentication needs to be configured.");
951                 }
952 
953                 IkeAuthEapConfig ikeAuthEapConfig = (IkeAuthEapConfig) mLocalAuthConfig;
954                 if (!ikeAuthEapConfig.getEapConfig().areAllMethodsEapOnlySafe()) {
955                     throw new IllegalArgumentException(
956                             "Only EAP-only safe method allowed" + " when using EAP-only option.");
957                 }
958             }
959 
960             if (mLocalAuthConfig.mAuthMethod == IKE_AUTH_METHOD_PUB_KEY_SIGNATURE
961                     && mLocalIdentification.idType == IkeIdentification.ID_TYPE_KEY_ID) {
962                 throw new IllegalArgumentException(
963                         "It is not allowed to use KEY_ID as local ID when local authentication"
964                                 + " method is digital-signature-based");
965             }
966 
967             return new IkeSessionParams(
968                     mServerHostname,
969                     network,
970                     mSaProposalList.toArray(new IkeSaProposal[0]),
971                     mLocalIdentification,
972                     mRemoteIdentification,
973                     mLocalAuthConfig,
974                     mRemoteAuthConfig,
975                     mConfigRequestList.toArray(new IkeConfigAttribute[0]),
976                     mRetransTimeoutMsList,
977                     mIkeOptions,
978                     mHardLifetimeSec,
979                     mSoftLifetimeSec,
980                     mDpdDelaySec,
981                     mIsIkeFragmentationSupported);
982         }
983 
984         // TODO: add methods for supporting IKE fragmentation.
985     }
986 }
987