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 
20 import static com.android.internal.annotations.VisibleForTesting.Visibility;
21 
22 import android.annotation.NonNull;
23 import android.net.eap.EapSessionConfig;
24 import android.net.eap.EapSessionConfig.EapAkaConfig;
25 import android.net.eap.EapSessionConfig.EapAkaPrimeConfig;
26 import android.net.eap.EapSessionConfig.EapMethodConfig;
27 import android.net.eap.EapSessionConfig.EapMsChapV2Config;
28 import android.net.eap.EapSessionConfig.EapSimConfig;
29 import android.net.eap.EapSessionConfig.EapTtlsConfig;
30 import android.net.eap.EapSessionConfig.EapUiccConfig;
31 import android.os.PersistableBundle;
32 
33 import com.android.internal.annotations.VisibleForTesting;
34 import com.android.server.vcn.util.PersistableBundleUtils;
35 
36 import java.security.cert.CertificateEncodingException;
37 import java.security.cert.X509Certificate;
38 import java.util.Objects;
39 
40 /**
41  * Provides utility methods to convert EapSessionConfig to/from PersistableBundle.
42  *
43  * @hide
44  */
45 @VisibleForTesting(visibility = Visibility.PRIVATE)
46 public final class EapSessionConfigUtils {
47     private static final String EAP_ID_KEY = "EAP_ID_KEY";
48     private static final String EAP_SIM_CONFIG_KEY = "EAP_SIM_CONFIG_KEY";
49     private static final String EAP_TTLS_CONFIG_KEY = "EAP_TTLS_CONFIG_KEY";
50     private static final String EAP_AKA_CONFIG_KEY = "EAP_AKA_CONFIG_KEY";
51     private static final String EAP_MSCHAP_V2_CONFIG_KEY = "EAP_MSCHAP_V2_CONFIG_KEY";
52     private static final String EAP_AKA_PRIME_CONFIG_KEY = "EAP_AKA_PRIME_CONFIG_KEY";
53 
54     /** Serializes an EapSessionConfig to a PersistableBundle. */
55     @NonNull
toPersistableBundle(@onNull EapSessionConfig config)56     public static PersistableBundle toPersistableBundle(@NonNull EapSessionConfig config) {
57         final PersistableBundle result = new PersistableBundle();
58 
59         result.putPersistableBundle(
60                 EAP_ID_KEY, PersistableBundleUtils.fromByteArray(config.getEapIdentity()));
61 
62         if (config.getEapSimConfig() != null) {
63             result.putPersistableBundle(
64                     EAP_SIM_CONFIG_KEY,
65                     EapSimConfigUtils.toPersistableBundle(config.getEapSimConfig()));
66         }
67 
68         if (config.getEapTtlsConfig() != null) {
69             result.putPersistableBundle(
70                     EAP_TTLS_CONFIG_KEY,
71                     EapTtlsConfigUtils.toPersistableBundle(config.getEapTtlsConfig()));
72         }
73 
74         if (config.getEapAkaConfig() != null) {
75             result.putPersistableBundle(
76                     EAP_AKA_CONFIG_KEY,
77                     EapAkaConfigUtils.toPersistableBundle(config.getEapAkaConfig()));
78         }
79 
80         if (config.getEapMsChapV2Config() != null) {
81             result.putPersistableBundle(
82                     EAP_MSCHAP_V2_CONFIG_KEY,
83                     EapMsChapV2ConfigUtils.toPersistableBundle(config.getEapMsChapV2Config()));
84         }
85 
86         if (config.getEapAkaPrimeConfig() != null) {
87             result.putPersistableBundle(
88                     EAP_AKA_PRIME_CONFIG_KEY,
89                     EapAkaPrimeConfigUtils.toPersistableBundle(config.getEapAkaPrimeConfig()));
90         }
91 
92         return result;
93     }
94 
95     /** Constructs an EapSessionConfig by deserializing a PersistableBundle. */
96     @NonNull
fromPersistableBundle(@onNull PersistableBundle in)97     public static EapSessionConfig fromPersistableBundle(@NonNull PersistableBundle in) {
98         Objects.requireNonNull(in, "PersistableBundle was null");
99 
100         final EapSessionConfig.Builder builder = new EapSessionConfig.Builder();
101 
102         final PersistableBundle eapIdBundle = in.getPersistableBundle(EAP_ID_KEY);
103         Objects.requireNonNull(eapIdBundle, "EAP ID was null");
104         builder.setEapIdentity(PersistableBundleUtils.toByteArray(eapIdBundle));
105 
106         final PersistableBundle simBundle = in.getPersistableBundle(EAP_SIM_CONFIG_KEY);
107         if (simBundle != null) {
108             EapSimConfigUtils.setBuilderByReadingPersistableBundle(simBundle, builder);
109         }
110 
111         final PersistableBundle ttlsBundle = in.getPersistableBundle(EAP_TTLS_CONFIG_KEY);
112         if (ttlsBundle != null) {
113             EapTtlsConfigUtils.setBuilderByReadingPersistableBundle(ttlsBundle, builder);
114         }
115 
116         final PersistableBundle akaBundle = in.getPersistableBundle(EAP_AKA_CONFIG_KEY);
117         if (akaBundle != null) {
118             EapAkaConfigUtils.setBuilderByReadingPersistableBundle(akaBundle, builder);
119         }
120 
121         final PersistableBundle msChapV2Bundle = in.getPersistableBundle(EAP_MSCHAP_V2_CONFIG_KEY);
122         if (msChapV2Bundle != null) {
123             EapMsChapV2ConfigUtils.setBuilderByReadingPersistableBundle(msChapV2Bundle, builder);
124         }
125 
126         final PersistableBundle akaPrimeBundle = in.getPersistableBundle(EAP_AKA_PRIME_CONFIG_KEY);
127         if (akaPrimeBundle != null) {
128             EapAkaPrimeConfigUtils.setBuilderByReadingPersistableBundle(akaPrimeBundle, builder);
129         }
130 
131         return builder.build();
132     }
133 
134     private static class EapMethodConfigUtils {
135         private static final String METHOD_TYPE = "METHOD_TYPE";
136 
137         /** Serializes an EapMethodConfig to a PersistableBundle. */
138         @NonNull
toPersistableBundle(@onNull EapMethodConfig config)139         public static PersistableBundle toPersistableBundle(@NonNull EapMethodConfig config) {
140             final PersistableBundle result = new PersistableBundle();
141             result.putInt(METHOD_TYPE, config.getMethodType());
142             return result;
143         }
144     }
145 
146     private static class EapUiccConfigUtils extends EapMethodConfigUtils {
147         static final String SUB_ID_KEY = "SUB_ID_KEY";
148         static final String APP_TYPE_KEY = "APP_TYPE_KEY";
149 
150         @NonNull
toPersistableBundle(@onNull EapUiccConfig config)151         protected static PersistableBundle toPersistableBundle(@NonNull EapUiccConfig config) {
152             final PersistableBundle result = EapMethodConfigUtils.toPersistableBundle(config);
153             result.putInt(SUB_ID_KEY, config.getSubId());
154             result.putInt(APP_TYPE_KEY, config.getAppType());
155 
156             return result;
157         }
158     }
159 
160     private static final class EapSimConfigUtils extends EapUiccConfigUtils {
161         @NonNull
toPersistableBundle(EapSimConfig config)162         public static PersistableBundle toPersistableBundle(EapSimConfig config) {
163             return EapUiccConfigUtils.toPersistableBundle(config);
164         }
165 
setBuilderByReadingPersistableBundle( @onNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder)166         public static void setBuilderByReadingPersistableBundle(
167                 @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) {
168             Objects.requireNonNull(in, "PersistableBundle was null");
169             builder.setEapSimConfig(in.getInt(SUB_ID_KEY), in.getInt(APP_TYPE_KEY));
170         }
171     }
172 
173     private static class EapAkaConfigUtils extends EapUiccConfigUtils {
174         @NonNull
toPersistableBundle(@onNull EapAkaConfig config)175         public static PersistableBundle toPersistableBundle(@NonNull EapAkaConfig config) {
176             return EapUiccConfigUtils.toPersistableBundle(config);
177         }
178 
setBuilderByReadingPersistableBundle( @onNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder)179         public static void setBuilderByReadingPersistableBundle(
180                 @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) {
181             Objects.requireNonNull(in, "PersistableBundle was null");
182             builder.setEapAkaConfig(in.getInt(SUB_ID_KEY), in.getInt(APP_TYPE_KEY));
183         }
184     }
185 
186     private static final class EapAkaPrimeConfigUtils extends EapAkaConfigUtils {
187         private static final String NETWORK_NAME_KEY = "NETWORK_NAME_KEY";
188         private static final String ALL_MISMATCHED_NETWORK_KEY = "ALL_MISMATCHED_NETWORK_KEY";
189 
190         @NonNull
toPersistableBundle(@onNull EapAkaPrimeConfig config)191         public static PersistableBundle toPersistableBundle(@NonNull EapAkaPrimeConfig config) {
192             final PersistableBundle result = EapUiccConfigUtils.toPersistableBundle(config);
193             result.putString(NETWORK_NAME_KEY, config.getNetworkName());
194             result.putBoolean(ALL_MISMATCHED_NETWORK_KEY, config.allowsMismatchedNetworkNames());
195 
196             return result;
197         }
198 
setBuilderByReadingPersistableBundle( @onNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder)199         public static void setBuilderByReadingPersistableBundle(
200                 @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) {
201             Objects.requireNonNull(in, "PersistableBundle was null");
202             builder.setEapAkaPrimeConfig(
203                     in.getInt(SUB_ID_KEY),
204                     in.getInt(APP_TYPE_KEY),
205                     in.getString(NETWORK_NAME_KEY),
206                     in.getBoolean(ALL_MISMATCHED_NETWORK_KEY));
207         }
208     }
209 
210     private static final class EapMsChapV2ConfigUtils extends EapMethodConfigUtils {
211         private static final String USERNAME_KEY = "USERNAME_KEY";
212         private static final String PASSWORD_KEY = "PASSWORD_KEY";
213 
214         @NonNull
toPersistableBundle(@onNull EapMsChapV2Config config)215         public static PersistableBundle toPersistableBundle(@NonNull EapMsChapV2Config config) {
216             final PersistableBundle result = EapMethodConfigUtils.toPersistableBundle(config);
217             result.putString(USERNAME_KEY, config.getUsername());
218             result.putString(PASSWORD_KEY, config.getPassword());
219 
220             return result;
221         }
222 
setBuilderByReadingPersistableBundle( @onNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder)223         public static void setBuilderByReadingPersistableBundle(
224                 @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) {
225             Objects.requireNonNull(in, "PersistableBundle was null");
226             builder.setEapMsChapV2Config(in.getString(USERNAME_KEY), in.getString(PASSWORD_KEY));
227         }
228     }
229 
230     private static final class EapTtlsConfigUtils extends EapMethodConfigUtils {
231         private static final String TRUST_CERT_KEY = "TRUST_CERT_KEY";
232         private static final String EAP_SESSION_CONFIG_KEY = "EAP_SESSION_CONFIG_KEY";
233 
234         @NonNull
toPersistableBundle(@onNull EapTtlsConfig config)235         public static PersistableBundle toPersistableBundle(@NonNull EapTtlsConfig config) {
236             final PersistableBundle result = EapMethodConfigUtils.toPersistableBundle(config);
237             try {
238                 if (config.getServerCaCert() != null) {
239                     final PersistableBundle caBundle =
240                             PersistableBundleUtils.fromByteArray(
241                                     config.getServerCaCert().getEncoded());
242                     result.putPersistableBundle(TRUST_CERT_KEY, caBundle);
243                 }
244             } catch (CertificateEncodingException e) {
245                 throw new IllegalStateException("Fail to encode the certificate");
246             }
247 
248             result.putPersistableBundle(
249                     EAP_SESSION_CONFIG_KEY,
250                     EapSessionConfigUtils.toPersistableBundle(config.getInnerEapSessionConfig()));
251 
252             return result;
253         }
254 
setBuilderByReadingPersistableBundle( @onNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder)255         public static void setBuilderByReadingPersistableBundle(
256                 @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) {
257             Objects.requireNonNull(in, "PersistableBundle was null");
258 
259             final PersistableBundle caBundle = in.getPersistableBundle(TRUST_CERT_KEY);
260             X509Certificate caCert = null;
261             if (caBundle != null) {
262                 caCert =
263                         CertUtils.certificateFromByteArray(
264                                 PersistableBundleUtils.toByteArray(caBundle));
265             }
266 
267             final PersistableBundle eapSessionConfigBundle =
268                     in.getPersistableBundle(EAP_SESSION_CONFIG_KEY);
269             Objects.requireNonNull(eapSessionConfigBundle, "Inner EAP Session Config was null");
270             final EapSessionConfig eapSessionConfig =
271                     EapSessionConfigUtils.fromPersistableBundle(eapSessionConfigBundle);
272 
273             builder.setEapTtlsConfig(caCert, eapSessionConfig);
274         }
275     }
276 }
277