• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.vcn.persistablebundleutils;
18 
19 import static android.system.OsConstants.AF_INET;
20 import static android.system.OsConstants.AF_INET6;
21 
22 import static com.android.internal.annotations.VisibleForTesting.Visibility;
23 
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.net.InetAddresses;
27 import android.net.eap.EapSessionConfig;
28 import android.net.ipsec.ike.IkeSaProposal;
29 import android.net.ipsec.ike.IkeSessionParams;
30 import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv4PcscfServer;
31 import android.net.ipsec.ike.IkeSessionParams.ConfigRequestIpv6PcscfServer;
32 import android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig;
33 import android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignLocalConfig;
34 import android.net.ipsec.ike.IkeSessionParams.IkeAuthDigitalSignRemoteConfig;
35 import android.net.ipsec.ike.IkeSessionParams.IkeAuthEapConfig;
36 import android.net.ipsec.ike.IkeSessionParams.IkeAuthPskConfig;
37 import android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest;
38 import android.os.PersistableBundle;
39 import android.util.ArraySet;
40 import android.util.Log;
41 
42 import com.android.internal.annotations.VisibleForTesting;
43 import com.android.server.vcn.util.PersistableBundleUtils;
44 
45 import java.net.InetAddress;
46 import java.security.PrivateKey;
47 import java.security.cert.CertificateEncodingException;
48 import java.security.cert.X509Certificate;
49 import java.util.ArrayList;
50 import java.util.Arrays;
51 import java.util.List;
52 import java.util.Objects;
53 import java.util.Set;
54 
55 /**
56  * Abstract utility class to convert IkeSessionParams to/from PersistableBundle.
57  *
58  * @hide
59  */
60 @VisibleForTesting(visibility = Visibility.PRIVATE)
61 public final class IkeSessionParamsUtils {
62     private static final String TAG = IkeSessionParamsUtils.class.getSimpleName();
63 
64     private static final String SERVER_HOST_NAME_KEY = "SERVER_HOST_NAME_KEY";
65     private static final String SA_PROPOSALS_KEY = "SA_PROPOSALS_KEY";
66     private static final String LOCAL_ID_KEY = "LOCAL_ID_KEY";
67     private static final String REMOTE_ID_KEY = "REMOTE_ID_KEY";
68     private static final String LOCAL_AUTH_KEY = "LOCAL_AUTH_KEY";
69     private static final String REMOTE_AUTH_KEY = "REMOTE_AUTH_KEY";
70     private static final String CONFIG_REQUESTS_KEY = "CONFIG_REQUESTS_KEY";
71     private static final String RETRANS_TIMEOUTS_KEY = "RETRANS_TIMEOUTS_KEY";
72     private static final String HARD_LIFETIME_SEC_KEY = "HARD_LIFETIME_SEC_KEY";
73     private static final String SOFT_LIFETIME_SEC_KEY = "SOFT_LIFETIME_SEC_KEY";
74     private static final String DPD_DELAY_SEC_KEY = "DPD_DELAY_SEC_KEY";
75     private static final String NATT_KEEPALIVE_DELAY_SEC_KEY = "NATT_KEEPALIVE_DELAY_SEC_KEY";
76     private static final String IKE_OPTIONS_KEY = "IKE_OPTIONS_KEY";
77 
78     // TODO: b/243181760 Use the IKE API when they are exposed
79     @VisibleForTesting(visibility = Visibility.PRIVATE)
80     public static final int IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION = 6;
81 
82     @VisibleForTesting(visibility = Visibility.PRIVATE)
83     public static final int IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES = 7;
84 
85     private static final Set<Integer> IKE_OPTIONS = new ArraySet<>();
86 
87     static {
88         IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID);
89         IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH);
90         IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_MOBIKE);
91         IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500);
92         IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT);
93         IKE_OPTIONS.add(IkeSessionParams.IKE_OPTION_REKEY_MOBILITY);
94         IKE_OPTIONS.add(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION);
95         IKE_OPTIONS.add(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES);
96     }
97 
98     /**
99      * Check if an IKE option is supported in the IPsec module installed on the device
100      *
101      * <p>This method ensures caller to safely access options that are added between dessert
102      * releases.
103      */
104     @VisibleForTesting(visibility = Visibility.PRIVATE)
isIkeOptionValid(int option)105     public static boolean isIkeOptionValid(int option) {
106         try {
107             new IkeSessionParams.Builder().addIkeOption(option);
108             return true;
109         } catch (IllegalArgumentException e) {
110             Log.d(TAG, "Option not supported; discarding: " + option);
111             return false;
112         }
113     }
114 
115     /** Serializes an IkeSessionParams to a PersistableBundle. */
116     @NonNull
toPersistableBundle(@onNull IkeSessionParams params)117     public static PersistableBundle toPersistableBundle(@NonNull IkeSessionParams params) {
118         if (params.getNetwork() != null || params.getIke3gppExtension() != null) {
119             throw new IllegalStateException(
120                     "Cannot convert a IkeSessionParams with a caller configured network or with"
121                             + " 3GPP extension enabled");
122         }
123 
124         final PersistableBundle result = new PersistableBundle();
125 
126         result.putString(SERVER_HOST_NAME_KEY, params.getServerHostname());
127 
128         final PersistableBundle saProposalBundle =
129                 PersistableBundleUtils.fromList(
130                         params.getSaProposals(), IkeSaProposalUtils::toPersistableBundle);
131         result.putPersistableBundle(SA_PROPOSALS_KEY, saProposalBundle);
132 
133         result.putPersistableBundle(
134                 LOCAL_ID_KEY,
135                 IkeIdentificationUtils.toPersistableBundle(params.getLocalIdentification()));
136         result.putPersistableBundle(
137                 REMOTE_ID_KEY,
138                 IkeIdentificationUtils.toPersistableBundle(params.getRemoteIdentification()));
139 
140         result.putPersistableBundle(
141                 LOCAL_AUTH_KEY, AuthConfigUtils.toPersistableBundle(params.getLocalAuthConfig()));
142         result.putPersistableBundle(
143                 REMOTE_AUTH_KEY, AuthConfigUtils.toPersistableBundle(params.getRemoteAuthConfig()));
144 
145         final List<ConfigRequest> reqList = new ArrayList<>();
146         for (IkeConfigRequest req : params.getConfigurationRequests()) {
147             reqList.add(new ConfigRequest(req));
148         }
149         final PersistableBundle configReqListBundle =
150                 PersistableBundleUtils.fromList(reqList, ConfigRequest::toPersistableBundle);
151         result.putPersistableBundle(CONFIG_REQUESTS_KEY, configReqListBundle);
152 
153         result.putIntArray(RETRANS_TIMEOUTS_KEY, params.getRetransmissionTimeoutsMillis());
154         result.putInt(HARD_LIFETIME_SEC_KEY, params.getHardLifetimeSeconds());
155         result.putInt(SOFT_LIFETIME_SEC_KEY, params.getSoftLifetimeSeconds());
156         result.putInt(DPD_DELAY_SEC_KEY, params.getDpdDelaySeconds());
157         result.putInt(NATT_KEEPALIVE_DELAY_SEC_KEY, params.getNattKeepAliveDelaySeconds());
158 
159         // TODO: b/185941731 Make sure IkeSessionParamsUtils is automatically updated when a new
160         // IKE_OPTION is defined in IKE module and added in the IkeSessionParams
161         final List<Integer> enabledIkeOptions = new ArrayList<>();
162         for (int option : IKE_OPTIONS) {
163             if (isIkeOptionValid(option) && params.hasIkeOption(option)) {
164                 enabledIkeOptions.add(option);
165             }
166         }
167 
168         final int[] optionArray = enabledIkeOptions.stream().mapToInt(i -> i).toArray();
169         result.putIntArray(IKE_OPTIONS_KEY, optionArray);
170 
171         return result;
172     }
173 
174     /** Constructs an IkeSessionParams by deserializing a PersistableBundle. */
175     @NonNull
fromPersistableBundle(@onNull PersistableBundle in)176     public static IkeSessionParams fromPersistableBundle(@NonNull PersistableBundle in) {
177         Objects.requireNonNull(in, "PersistableBundle is null");
178 
179         final IkeSessionParams.Builder builder = new IkeSessionParams.Builder();
180 
181         builder.setServerHostname(in.getString(SERVER_HOST_NAME_KEY));
182 
183         PersistableBundle proposalBundle = in.getPersistableBundle(SA_PROPOSALS_KEY);
184         Objects.requireNonNull(in, "SA Proposals was null");
185         List<IkeSaProposal> saProposals =
186                 PersistableBundleUtils.toList(
187                         proposalBundle, IkeSaProposalUtils::fromPersistableBundle);
188         for (IkeSaProposal proposal : saProposals) {
189             builder.addSaProposal(proposal);
190         }
191 
192         builder.setLocalIdentification(
193                 IkeIdentificationUtils.fromPersistableBundle(
194                         in.getPersistableBundle(LOCAL_ID_KEY)));
195         builder.setRemoteIdentification(
196                 IkeIdentificationUtils.fromPersistableBundle(
197                         in.getPersistableBundle(REMOTE_ID_KEY)));
198 
199         AuthConfigUtils.setBuilderByReadingPersistableBundle(
200                 in.getPersistableBundle(LOCAL_AUTH_KEY),
201                 in.getPersistableBundle(REMOTE_AUTH_KEY),
202                 builder);
203 
204         builder.setRetransmissionTimeoutsMillis(in.getIntArray(RETRANS_TIMEOUTS_KEY));
205         builder.setLifetimeSeconds(
206                 in.getInt(HARD_LIFETIME_SEC_KEY), in.getInt(SOFT_LIFETIME_SEC_KEY));
207         builder.setDpdDelaySeconds(in.getInt(DPD_DELAY_SEC_KEY));
208         builder.setNattKeepAliveDelaySeconds(in.getInt(NATT_KEEPALIVE_DELAY_SEC_KEY));
209 
210         final PersistableBundle configReqListBundle = in.getPersistableBundle(CONFIG_REQUESTS_KEY);
211         Objects.requireNonNull(configReqListBundle, "Config request list was null");
212         final List<ConfigRequest> reqList =
213                 PersistableBundleUtils.toList(configReqListBundle, ConfigRequest::new);
214         for (ConfigRequest req : reqList) {
215             switch (req.type) {
216                 case ConfigRequest.IPV4_P_CSCF_ADDRESS:
217                     if (req.address == null) {
218                         builder.addPcscfServerRequest(AF_INET);
219                     } else {
220                         builder.addPcscfServerRequest(req.address);
221                     }
222                     break;
223                 case ConfigRequest.IPV6_P_CSCF_ADDRESS:
224                     if (req.address == null) {
225                         builder.addPcscfServerRequest(AF_INET6);
226                     } else {
227                         builder.addPcscfServerRequest(req.address);
228                     }
229                     break;
230                 default:
231                     throw new IllegalArgumentException(
232                             "Unrecognized config request type: " + req.type);
233             }
234         }
235 
236         // Clear IKE Options that are by default enabled
237         for (int option : IKE_OPTIONS) {
238             if (isIkeOptionValid(option)) {
239                 builder.removeIkeOption(option);
240             }
241         }
242 
243         final int[] optionArray = in.getIntArray(IKE_OPTIONS_KEY);
244         for (int option : optionArray) {
245             if (isIkeOptionValid(option)) {
246                 builder.addIkeOption(option);
247             }
248         }
249 
250         return builder.build();
251     }
252 
253     private static final class AuthConfigUtils {
254         private static final int IKE_AUTH_METHOD_PSK = 1;
255         private static final int IKE_AUTH_METHOD_PUB_KEY_SIGNATURE = 2;
256         private static final int IKE_AUTH_METHOD_EAP = 3;
257 
258         private static final String AUTH_METHOD_KEY = "AUTH_METHOD_KEY";
259 
260         @NonNull
toPersistableBundle(@onNull IkeAuthConfig authConfig)261         public static PersistableBundle toPersistableBundle(@NonNull IkeAuthConfig authConfig) {
262             if (authConfig instanceof IkeAuthPskConfig) {
263                 IkeAuthPskConfig config = (IkeAuthPskConfig) authConfig;
264                 return IkeAuthPskConfigUtils.toPersistableBundle(
265                         config, createPersistableBundle(IKE_AUTH_METHOD_PSK));
266             } else if (authConfig instanceof IkeAuthDigitalSignLocalConfig) {
267                 IkeAuthDigitalSignLocalConfig config = (IkeAuthDigitalSignLocalConfig) authConfig;
268                 return IkeAuthDigitalSignConfigUtils.toPersistableBundle(
269                         config, createPersistableBundle(IKE_AUTH_METHOD_PUB_KEY_SIGNATURE));
270             } else if (authConfig instanceof IkeAuthDigitalSignRemoteConfig) {
271                 IkeAuthDigitalSignRemoteConfig config = (IkeAuthDigitalSignRemoteConfig) authConfig;
272                 return IkeAuthDigitalSignConfigUtils.toPersistableBundle(
273                         config, createPersistableBundle(IKE_AUTH_METHOD_PUB_KEY_SIGNATURE));
274             } else if (authConfig instanceof IkeAuthEapConfig) {
275                 IkeAuthEapConfig config = (IkeAuthEapConfig) authConfig;
276                 return IkeAuthEapConfigUtils.toPersistableBundle(
277                         config, createPersistableBundle(IKE_AUTH_METHOD_EAP));
278             } else {
279                 throw new IllegalStateException("Invalid IkeAuthConfig subclass");
280             }
281         }
282 
createPersistableBundle(int type)283         private static PersistableBundle createPersistableBundle(int type) {
284             final PersistableBundle result = new PersistableBundle();
285             result.putInt(AUTH_METHOD_KEY, type);
286             return result;
287         }
288 
setBuilderByReadingPersistableBundle( @onNull PersistableBundle localAuthBundle, @NonNull PersistableBundle remoteAuthBundle, @NonNull IkeSessionParams.Builder builder)289         public static void setBuilderByReadingPersistableBundle(
290                 @NonNull PersistableBundle localAuthBundle,
291                 @NonNull PersistableBundle remoteAuthBundle,
292                 @NonNull IkeSessionParams.Builder builder) {
293             Objects.requireNonNull(localAuthBundle, "localAuthBundle was null");
294             Objects.requireNonNull(remoteAuthBundle, "remoteAuthBundle was null");
295 
296             final int localMethodType = localAuthBundle.getInt(AUTH_METHOD_KEY);
297             final int remoteMethodType = remoteAuthBundle.getInt(AUTH_METHOD_KEY);
298             switch (localMethodType) {
299                 case IKE_AUTH_METHOD_PSK:
300                     if (remoteMethodType != IKE_AUTH_METHOD_PSK) {
301                         throw new IllegalArgumentException(
302                                 "Expect remote auth method to be PSK based, but was "
303                                         + remoteMethodType);
304                     }
305                     IkeAuthPskConfigUtils.setBuilderByReadingPersistableBundle(
306                             localAuthBundle, remoteAuthBundle, builder);
307                     return;
308                 case IKE_AUTH_METHOD_PUB_KEY_SIGNATURE:
309                     if (remoteMethodType != IKE_AUTH_METHOD_PUB_KEY_SIGNATURE) {
310                         throw new IllegalArgumentException(
311                                 "Expect remote auth method to be digital signature based, but was "
312                                         + remoteMethodType);
313                     }
314                     IkeAuthDigitalSignConfigUtils.setBuilderByReadingPersistableBundle(
315                             localAuthBundle, remoteAuthBundle, builder);
316                     return;
317                 case IKE_AUTH_METHOD_EAP:
318                     if (remoteMethodType != IKE_AUTH_METHOD_PUB_KEY_SIGNATURE) {
319                         throw new IllegalArgumentException(
320                                 "When using EAP for local authentication, expect remote auth"
321                                         + " method to be digital signature based, but was "
322                                         + remoteMethodType);
323                     }
324                     IkeAuthEapConfigUtils.setBuilderByReadingPersistableBundle(
325                             localAuthBundle, remoteAuthBundle, builder);
326                     return;
327                 default:
328                     throw new IllegalArgumentException(
329                             "Invalid EAP method type " + localMethodType);
330             }
331         }
332     }
333 
334     private static final class IkeAuthPskConfigUtils {
335         private static final String PSK_KEY = "PSK_KEY";
336 
337         @NonNull
toPersistableBundle( @onNull IkeAuthPskConfig config, @NonNull PersistableBundle result)338         public static PersistableBundle toPersistableBundle(
339                 @NonNull IkeAuthPskConfig config, @NonNull PersistableBundle result) {
340             result.putPersistableBundle(
341                     PSK_KEY, PersistableBundleUtils.fromByteArray(config.getPsk()));
342             return result;
343         }
344 
setBuilderByReadingPersistableBundle( @onNull PersistableBundle localAuthBundle, @NonNull PersistableBundle remoteAuthBundle, @NonNull IkeSessionParams.Builder builder)345         public static void setBuilderByReadingPersistableBundle(
346                 @NonNull PersistableBundle localAuthBundle,
347                 @NonNull PersistableBundle remoteAuthBundle,
348                 @NonNull IkeSessionParams.Builder builder) {
349             Objects.requireNonNull(localAuthBundle, "localAuthBundle was null");
350             Objects.requireNonNull(remoteAuthBundle, "remoteAuthBundle was null");
351 
352             final PersistableBundle localPskBundle = localAuthBundle.getPersistableBundle(PSK_KEY);
353             final PersistableBundle remotePskBundle =
354                     remoteAuthBundle.getPersistableBundle(PSK_KEY);
355             Objects.requireNonNull(localAuthBundle, "Local PSK was null");
356             Objects.requireNonNull(remoteAuthBundle, "Remote PSK was null");
357 
358             final byte[] localPsk = PersistableBundleUtils.toByteArray(localPskBundle);
359             final byte[] remotePsk = PersistableBundleUtils.toByteArray(remotePskBundle);
360             if (!Arrays.equals(localPsk, remotePsk)) {
361                 throw new IllegalArgumentException("Local PSK and remote PSK are different");
362             }
363             builder.setAuthPsk(localPsk);
364         }
365     }
366 
367     private static class IkeAuthDigitalSignConfigUtils {
368         private static final String END_CERT_KEY = "END_CERT_KEY";
369         private static final String INTERMEDIATE_CERTS_KEY = "INTERMEDIATE_CERTS_KEY";
370         private static final String PRIVATE_KEY_KEY = "PRIVATE_KEY_KEY";
371         private static final String TRUST_CERT_KEY = "TRUST_CERT_KEY";
372 
373         @NonNull
toPersistableBundle( @onNull IkeAuthDigitalSignLocalConfig config, @NonNull PersistableBundle result)374         public static PersistableBundle toPersistableBundle(
375                 @NonNull IkeAuthDigitalSignLocalConfig config, @NonNull PersistableBundle result) {
376             try {
377                 result.putPersistableBundle(
378                         END_CERT_KEY,
379                         PersistableBundleUtils.fromByteArray(
380                                 config.getClientEndCertificate().getEncoded()));
381 
382                 final List<X509Certificate> certList = config.getIntermediateCertificates();
383                 final List<byte[]> encodedCertList = new ArrayList<>(certList.size());
384                 for (X509Certificate cert : certList) {
385                     encodedCertList.add(cert.getEncoded());
386                 }
387 
388                 final PersistableBundle certsBundle =
389                         PersistableBundleUtils.fromList(
390                                 encodedCertList, PersistableBundleUtils::fromByteArray);
391                 result.putPersistableBundle(INTERMEDIATE_CERTS_KEY, certsBundle);
392             } catch (CertificateEncodingException e) {
393                 throw new IllegalArgumentException("Fail to encode certificate");
394             }
395 
396             // TODO: b/170670506 Consider putting PrivateKey in Android KeyStore
397             result.putPersistableBundle(
398                     PRIVATE_KEY_KEY,
399                     PersistableBundleUtils.fromByteArray(config.getPrivateKey().getEncoded()));
400             return result;
401         }
402 
403         @NonNull
toPersistableBundle( @onNull IkeAuthDigitalSignRemoteConfig config, @NonNull PersistableBundle result)404         public static PersistableBundle toPersistableBundle(
405                 @NonNull IkeAuthDigitalSignRemoteConfig config, @NonNull PersistableBundle result) {
406             try {
407                 X509Certificate caCert = config.getRemoteCaCert();
408                 if (caCert != null) {
409                     result.putPersistableBundle(
410                             TRUST_CERT_KEY,
411                             PersistableBundleUtils.fromByteArray(caCert.getEncoded()));
412                 }
413             } catch (CertificateEncodingException e) {
414                 throw new IllegalArgumentException("Fail to encode the certificate");
415             }
416 
417             return result;
418         }
419 
setBuilderByReadingPersistableBundle( @onNull PersistableBundle localAuthBundle, @NonNull PersistableBundle remoteAuthBundle, @NonNull IkeSessionParams.Builder builder)420         public static void setBuilderByReadingPersistableBundle(
421                 @NonNull PersistableBundle localAuthBundle,
422                 @NonNull PersistableBundle remoteAuthBundle,
423                 @NonNull IkeSessionParams.Builder builder) {
424             Objects.requireNonNull(localAuthBundle, "localAuthBundle was null");
425             Objects.requireNonNull(remoteAuthBundle, "remoteAuthBundle was null");
426 
427             // Deserialize localAuth
428             final PersistableBundle endCertBundle =
429                     localAuthBundle.getPersistableBundle(END_CERT_KEY);
430             Objects.requireNonNull(endCertBundle, "End cert was null");
431             final byte[] encodedCert = PersistableBundleUtils.toByteArray(endCertBundle);
432             final X509Certificate endCert = CertUtils.certificateFromByteArray(encodedCert);
433 
434             final PersistableBundle certsBundle =
435                     localAuthBundle.getPersistableBundle(INTERMEDIATE_CERTS_KEY);
436             Objects.requireNonNull(certsBundle, "Intermediate certs was null");
437             final List<byte[]> encodedCertList =
438                     PersistableBundleUtils.toList(certsBundle, PersistableBundleUtils::toByteArray);
439             final List<X509Certificate> certList = new ArrayList<>(encodedCertList.size());
440             for (byte[] encoded : encodedCertList) {
441                 certList.add(CertUtils.certificateFromByteArray(encoded));
442             }
443 
444             final PersistableBundle privateKeyBundle =
445                     localAuthBundle.getPersistableBundle(PRIVATE_KEY_KEY);
446             Objects.requireNonNull(privateKeyBundle, "PrivateKey bundle was null");
447             final PrivateKey privateKey =
448                     CertUtils.privateKeyFromByteArray(
449                             PersistableBundleUtils.toByteArray(privateKeyBundle));
450 
451             // Deserialize remoteAuth
452             final PersistableBundle trustCertBundle =
453                     remoteAuthBundle.getPersistableBundle(TRUST_CERT_KEY);
454 
455             X509Certificate caCert = null;
456             if (trustCertBundle != null) {
457                 final byte[] encodedCaCert = PersistableBundleUtils.toByteArray(trustCertBundle);
458                 caCert = CertUtils.certificateFromByteArray(encodedCaCert);
459             }
460 
461             builder.setAuthDigitalSignature(caCert, endCert, certList, privateKey);
462         }
463     }
464 
465     private static final class IkeAuthEapConfigUtils {
466         private static final String EAP_CONFIG_KEY = "EAP_CONFIG_KEY";
467 
468         @NonNull
toPersistableBundle( @onNull IkeAuthEapConfig config, @NonNull PersistableBundle result)469         public static PersistableBundle toPersistableBundle(
470                 @NonNull IkeAuthEapConfig config, @NonNull PersistableBundle result) {
471             result.putPersistableBundle(
472                     EAP_CONFIG_KEY,
473                     EapSessionConfigUtils.toPersistableBundle(config.getEapConfig()));
474             return result;
475         }
476 
setBuilderByReadingPersistableBundle( @onNull PersistableBundle localAuthBundle, @NonNull PersistableBundle remoteAuthBundle, @NonNull IkeSessionParams.Builder builder)477         public static void setBuilderByReadingPersistableBundle(
478                 @NonNull PersistableBundle localAuthBundle,
479                 @NonNull PersistableBundle remoteAuthBundle,
480                 @NonNull IkeSessionParams.Builder builder) {
481             // Deserialize localAuth
482             final PersistableBundle eapBundle =
483                     localAuthBundle.getPersistableBundle(EAP_CONFIG_KEY);
484             Objects.requireNonNull(eapBundle, "EAP Config was null");
485             final EapSessionConfig eapConfig =
486                     EapSessionConfigUtils.fromPersistableBundle(eapBundle);
487 
488             // Deserialize remoteAuth
489             final PersistableBundle trustCertBundle =
490                     remoteAuthBundle.getPersistableBundle(
491                             IkeAuthDigitalSignConfigUtils.TRUST_CERT_KEY);
492 
493             X509Certificate serverCaCert = null;
494             if (trustCertBundle != null) {
495                 final byte[] encodedCaCert = PersistableBundleUtils.toByteArray(trustCertBundle);
496                 serverCaCert = CertUtils.certificateFromByteArray(encodedCaCert);
497             }
498             builder.setAuthEap(serverCaCert, eapConfig);
499         }
500     }
501 
502     private static final class ConfigRequest {
503         private static final int IPV4_P_CSCF_ADDRESS = 1;
504         private static final int IPV6_P_CSCF_ADDRESS = 2;
505 
506         private static final String TYPE_KEY = "type";
507         private static final String ADDRESS_KEY = "address";
508 
509         public final int type;
510 
511         // Null when it is an empty request
512         @Nullable public final InetAddress address;
513 
ConfigRequest(IkeConfigRequest config)514         ConfigRequest(IkeConfigRequest config) {
515             if (config instanceof ConfigRequestIpv4PcscfServer) {
516                 type = IPV4_P_CSCF_ADDRESS;
517                 address = ((ConfigRequestIpv4PcscfServer) config).getAddress();
518             } else if (config instanceof ConfigRequestIpv6PcscfServer) {
519                 type = IPV6_P_CSCF_ADDRESS;
520                 address = ((ConfigRequestIpv6PcscfServer) config).getAddress();
521             } else {
522                 throw new IllegalStateException("Unknown TunnelModeChildConfigRequest");
523             }
524         }
525 
ConfigRequest(PersistableBundle in)526         ConfigRequest(PersistableBundle in) {
527             Objects.requireNonNull(in, "PersistableBundle was null");
528 
529             type = in.getInt(TYPE_KEY);
530 
531             String addressStr = in.getString(ADDRESS_KEY);
532             if (addressStr == null) {
533                 address = null;
534             } else {
535                 address = InetAddresses.parseNumericAddress(addressStr);
536             }
537         }
538 
539         @NonNull
toPersistableBundle()540         public PersistableBundle toPersistableBundle() {
541             final PersistableBundle result = new PersistableBundle();
542 
543             result.putInt(TYPE_KEY, type);
544             if (address != null) {
545                 result.putString(ADDRESS_KEY, address.getHostAddress());
546             }
547 
548             return result;
549         }
550     }
551 }
552