/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.vcn.persistablebundleutils; import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.NonNull; import android.net.eap.EapSessionConfig; import android.net.eap.EapSessionConfig.EapAkaConfig; import android.net.eap.EapSessionConfig.EapAkaPrimeConfig; import android.net.eap.EapSessionConfig.EapMethodConfig; import android.net.eap.EapSessionConfig.EapMsChapV2Config; import android.net.eap.EapSessionConfig.EapSimConfig; import android.net.eap.EapSessionConfig.EapTtlsConfig; import android.net.eap.EapSessionConfig.EapUiccConfig; import android.os.PersistableBundle; import com.android.internal.annotations.VisibleForTesting; import com.android.server.vcn.util.PersistableBundleUtils; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.util.Objects; /** * Provides utility methods to convert EapSessionConfig to/from PersistableBundle. * * @hide */ @VisibleForTesting(visibility = Visibility.PRIVATE) public final class EapSessionConfigUtils { private static final String EAP_ID_KEY = "EAP_ID_KEY"; private static final String EAP_SIM_CONFIG_KEY = "EAP_SIM_CONFIG_KEY"; private static final String EAP_TTLS_CONFIG_KEY = "EAP_TTLS_CONFIG_KEY"; private static final String EAP_AKA_CONFIG_KEY = "EAP_AKA_CONFIG_KEY"; private static final String EAP_MSCHAP_V2_CONFIG_KEY = "EAP_MSCHAP_V2_CONFIG_KEY"; private static final String EAP_AKA_PRIME_CONFIG_KEY = "EAP_AKA_PRIME_CONFIG_KEY"; /** Serializes an EapSessionConfig to a PersistableBundle. */ @NonNull public static PersistableBundle toPersistableBundle(@NonNull EapSessionConfig config) { final PersistableBundle result = new PersistableBundle(); result.putPersistableBundle( EAP_ID_KEY, PersistableBundleUtils.fromByteArray(config.getEapIdentity())); if (config.getEapSimConfig() != null) { result.putPersistableBundle( EAP_SIM_CONFIG_KEY, EapSimConfigUtils.toPersistableBundle(config.getEapSimConfig())); } if (config.getEapTtlsConfig() != null) { result.putPersistableBundle( EAP_TTLS_CONFIG_KEY, EapTtlsConfigUtils.toPersistableBundle(config.getEapTtlsConfig())); } if (config.getEapAkaConfig() != null) { result.putPersistableBundle( EAP_AKA_CONFIG_KEY, EapAkaConfigUtils.toPersistableBundle(config.getEapAkaConfig())); } if (config.getEapMsChapV2Config() != null) { result.putPersistableBundle( EAP_MSCHAP_V2_CONFIG_KEY, EapMsChapV2ConfigUtils.toPersistableBundle(config.getEapMsChapV2Config())); } if (config.getEapAkaPrimeConfig() != null) { result.putPersistableBundle( EAP_AKA_PRIME_CONFIG_KEY, EapAkaPrimeConfigUtils.toPersistableBundle(config.getEapAkaPrimeConfig())); } return result; } /** Constructs an EapSessionConfig by deserializing a PersistableBundle. */ @NonNull public static EapSessionConfig fromPersistableBundle(@NonNull PersistableBundle in) { Objects.requireNonNull(in, "PersistableBundle was null"); final EapSessionConfig.Builder builder = new EapSessionConfig.Builder(); final PersistableBundle eapIdBundle = in.getPersistableBundle(EAP_ID_KEY); Objects.requireNonNull(eapIdBundle, "EAP ID was null"); builder.setEapIdentity(PersistableBundleUtils.toByteArray(eapIdBundle)); final PersistableBundle simBundle = in.getPersistableBundle(EAP_SIM_CONFIG_KEY); if (simBundle != null) { EapSimConfigUtils.setBuilderByReadingPersistableBundle(simBundle, builder); } final PersistableBundle ttlsBundle = in.getPersistableBundle(EAP_TTLS_CONFIG_KEY); if (ttlsBundle != null) { EapTtlsConfigUtils.setBuilderByReadingPersistableBundle(ttlsBundle, builder); } final PersistableBundle akaBundle = in.getPersistableBundle(EAP_AKA_CONFIG_KEY); if (akaBundle != null) { EapAkaConfigUtils.setBuilderByReadingPersistableBundle(akaBundle, builder); } final PersistableBundle msChapV2Bundle = in.getPersistableBundle(EAP_MSCHAP_V2_CONFIG_KEY); if (msChapV2Bundle != null) { EapMsChapV2ConfigUtils.setBuilderByReadingPersistableBundle(msChapV2Bundle, builder); } final PersistableBundle akaPrimeBundle = in.getPersistableBundle(EAP_AKA_PRIME_CONFIG_KEY); if (akaPrimeBundle != null) { EapAkaPrimeConfigUtils.setBuilderByReadingPersistableBundle(akaPrimeBundle, builder); } return builder.build(); } private static class EapMethodConfigUtils { private static final String METHOD_TYPE = "METHOD_TYPE"; /** Serializes an EapMethodConfig to a PersistableBundle. */ @NonNull public static PersistableBundle toPersistableBundle(@NonNull EapMethodConfig config) { final PersistableBundle result = new PersistableBundle(); result.putInt(METHOD_TYPE, config.getMethodType()); return result; } } private static class EapUiccConfigUtils extends EapMethodConfigUtils { static final String SUB_ID_KEY = "SUB_ID_KEY"; static final String APP_TYPE_KEY = "APP_TYPE_KEY"; @NonNull protected static PersistableBundle toPersistableBundle(@NonNull EapUiccConfig config) { final PersistableBundle result = EapMethodConfigUtils.toPersistableBundle(config); result.putInt(SUB_ID_KEY, config.getSubId()); result.putInt(APP_TYPE_KEY, config.getAppType()); return result; } } private static final class EapSimConfigUtils extends EapUiccConfigUtils { @NonNull public static PersistableBundle toPersistableBundle(EapSimConfig config) { return EapUiccConfigUtils.toPersistableBundle(config); } public static void setBuilderByReadingPersistableBundle( @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) { Objects.requireNonNull(in, "PersistableBundle was null"); builder.setEapSimConfig(in.getInt(SUB_ID_KEY), in.getInt(APP_TYPE_KEY)); } } private static class EapAkaConfigUtils extends EapUiccConfigUtils { @NonNull public static PersistableBundle toPersistableBundle(@NonNull EapAkaConfig config) { return EapUiccConfigUtils.toPersistableBundle(config); } public static void setBuilderByReadingPersistableBundle( @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) { Objects.requireNonNull(in, "PersistableBundle was null"); builder.setEapAkaConfig(in.getInt(SUB_ID_KEY), in.getInt(APP_TYPE_KEY)); } } private static final class EapAkaPrimeConfigUtils extends EapAkaConfigUtils { private static final String NETWORK_NAME_KEY = "NETWORK_NAME_KEY"; private static final String ALL_MISMATCHED_NETWORK_KEY = "ALL_MISMATCHED_NETWORK_KEY"; @NonNull public static PersistableBundle toPersistableBundle(@NonNull EapAkaPrimeConfig config) { final PersistableBundle result = EapUiccConfigUtils.toPersistableBundle(config); result.putString(NETWORK_NAME_KEY, config.getNetworkName()); result.putBoolean(ALL_MISMATCHED_NETWORK_KEY, config.allowsMismatchedNetworkNames()); return result; } public static void setBuilderByReadingPersistableBundle( @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) { Objects.requireNonNull(in, "PersistableBundle was null"); builder.setEapAkaPrimeConfig( in.getInt(SUB_ID_KEY), in.getInt(APP_TYPE_KEY), in.getString(NETWORK_NAME_KEY), in.getBoolean(ALL_MISMATCHED_NETWORK_KEY)); } } private static final class EapMsChapV2ConfigUtils extends EapMethodConfigUtils { private static final String USERNAME_KEY = "USERNAME_KEY"; private static final String PASSWORD_KEY = "PASSWORD_KEY"; @NonNull public static PersistableBundle toPersistableBundle(@NonNull EapMsChapV2Config config) { final PersistableBundle result = EapMethodConfigUtils.toPersistableBundle(config); result.putString(USERNAME_KEY, config.getUsername()); result.putString(PASSWORD_KEY, config.getPassword()); return result; } public static void setBuilderByReadingPersistableBundle( @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) { Objects.requireNonNull(in, "PersistableBundle was null"); builder.setEapMsChapV2Config(in.getString(USERNAME_KEY), in.getString(PASSWORD_KEY)); } } private static final class EapTtlsConfigUtils extends EapMethodConfigUtils { private static final String TRUST_CERT_KEY = "TRUST_CERT_KEY"; private static final String EAP_SESSION_CONFIG_KEY = "EAP_SESSION_CONFIG_KEY"; @NonNull public static PersistableBundle toPersistableBundle(@NonNull EapTtlsConfig config) { final PersistableBundle result = EapMethodConfigUtils.toPersistableBundle(config); try { if (config.getServerCaCert() != null) { final PersistableBundle caBundle = PersistableBundleUtils.fromByteArray( config.getServerCaCert().getEncoded()); result.putPersistableBundle(TRUST_CERT_KEY, caBundle); } } catch (CertificateEncodingException e) { throw new IllegalStateException("Fail to encode the certificate"); } result.putPersistableBundle( EAP_SESSION_CONFIG_KEY, EapSessionConfigUtils.toPersistableBundle(config.getInnerEapSessionConfig())); return result; } public static void setBuilderByReadingPersistableBundle( @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) { Objects.requireNonNull(in, "PersistableBundle was null"); final PersistableBundle caBundle = in.getPersistableBundle(TRUST_CERT_KEY); X509Certificate caCert = null; if (caBundle != null) { caCert = CertUtils.certificateFromByteArray( PersistableBundleUtils.toByteArray(caBundle)); } final PersistableBundle eapSessionConfigBundle = in.getPersistableBundle(EAP_SESSION_CONFIG_KEY); Objects.requireNonNull(eapSessionConfigBundle, "Inner EAP Session Config was null"); final EapSessionConfig eapSessionConfig = EapSessionConfigUtils.fromPersistableBundle(eapSessionConfigBundle); builder.setEapTtlsConfig(caCert, eapSessionConfig); } } }