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