• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 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 com.google.android.iwlan.epdg;
18 
19 import android.net.ipsec.ike.SaProposal;
20 import android.util.Log;
21 import android.util.Pair;
22 
23 import java.util.Collections;
24 import java.util.Iterator;
25 import java.util.LinkedHashSet;
26 import java.util.List;
27 import java.util.Set;
28 
29 abstract class EpdgSaProposal {
30     private static final String TAG = EpdgSaProposal.class.getSimpleName();
31     private static final Set<Integer> VALID_DH_GROUPS;
32     private static final Set<Integer> VALID_KEY_LENGTHS;
33     protected static final Set<Integer> VALID_PRF_ALGOS;
34     private static final Set<Integer> VALID_INTEGRITY_ALGOS;
35     private static final Set<Integer> VALID_ENCRYPTION_ALGOS;
36     private static final Set<Integer> VALID_AEAD_ALGOS;
37 
38     private static final String CONFIG_TYPE_DH_GROUP = "dh group";
39     private static final String CONFIG_TYPE_KEY_LEN = "algorithm key length";
40     protected static final String CONFIG_TYPE_PRF_ALGO = "prf algorithm";
41     private static final String CONFIG_TYPE_INTEGRITY_ALGO = "integrity algorithm";
42     private static final String CONFIG_TYPE_ENCRYPT_ALGO = "encryption algorithm";
43     private static final String CONFIG_TYPE_AEAD_ALGO = "AEAD algorithm";
44 
45     private boolean mSaferAlgosPrioritized = false;
46 
47     /*
48      * Each transform below filled with high secured order and index of each value
49      * represents the priority.
50      * Safer transform has high priority and proposals will be orders based on
51      * the priority order.
52      * For example, DH Group 4096 has more priority compare to 3072, and 3072
53      * has more priority than 2048.
54      * With reference to 3GPP TS 33.210 and RFC 8221, high secured transforms
55      * are prioritized in IKE and CHILD SA proposals.
56      */
57     static {
58         VALID_DH_GROUPS =
59                 Collections.unmodifiableSet(
60                         new LinkedHashSet<Integer>(
61                                 List.of(
62                                         SaProposal.DH_GROUP_4096_BIT_MODP,
63                                         SaProposal.DH_GROUP_3072_BIT_MODP,
64                                         SaProposal.DH_GROUP_2048_BIT_MODP,
65                                         SaProposal.DH_GROUP_1536_BIT_MODP,
66                                         SaProposal.DH_GROUP_1024_BIT_MODP)));
67 
68         VALID_KEY_LENGTHS =
69                 Collections.unmodifiableSet(
70                         new LinkedHashSet<Integer>(
71                                 List.of(
72                                         SaProposal.KEY_LEN_AES_256,
73                                         SaProposal.KEY_LEN_AES_192,
74                                         SaProposal.KEY_LEN_AES_128)));
75 
76         VALID_ENCRYPTION_ALGOS =
77                 Collections.unmodifiableSet(
78                         new LinkedHashSet<Integer>(
79                                 List.of(
80                                         SaProposal.ENCRYPTION_ALGORITHM_AES_CBC,
81                                         SaProposal.ENCRYPTION_ALGORITHM_AES_CTR)));
82 
83         VALID_INTEGRITY_ALGOS =
84                 Collections.unmodifiableSet(
85                         new LinkedHashSet<Integer>(
86                                 List.of(
87                                         SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256,
88                                         SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192,
89                                         SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128,
90                                         SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96,
91                                         SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96)));
92 
93         VALID_AEAD_ALGOS =
94                 Collections.unmodifiableSet(
95                         new LinkedHashSet<Integer>(
96                                 List.of(
97                                         SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16,
98                                         SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12,
99                                         SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8)));
100 
101         VALID_PRF_ALGOS =
102                 Collections.unmodifiableSet(
103                         new LinkedHashSet<Integer>(
104                                 List.of(
105                                         SaProposal.PSEUDORANDOM_FUNCTION_SHA2_512,
106                                         SaProposal.PSEUDORANDOM_FUNCTION_SHA2_384,
107                                         SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256,
108                                         SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1,
109                                         SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC)));
110     }
111 
112     protected final LinkedHashSet<Integer> mProposedDhGroups = new LinkedHashSet<>();
113     protected final LinkedHashSet<Integer> mProposedIntegrityAlgos = new LinkedHashSet<>();
114     protected final LinkedHashSet<Pair<Integer, Integer>> mProposedEncryptAlgos =
115             new LinkedHashSet<>();
116     protected final LinkedHashSet<Pair<Integer, Integer>> mProposedAeadAlgos =
117             new LinkedHashSet<>();
118 
119     /**
120      * Add proposed DH groups by the carrier.
121      *
122      * @param dhGroups proposed DH groups
123      */
addProposedDhGroups(int[] dhGroups)124     public void addProposedDhGroups(int[] dhGroups) {
125         for (int dhGroup : dhGroups) {
126             if (validateConfig(dhGroup, VALID_DH_GROUPS, CONFIG_TYPE_DH_GROUP)) {
127                 mProposedDhGroups.add(dhGroup);
128             }
129         }
130     }
131 
132     /**
133      * Add proposed integrity algorithms by the carrier.
134      *
135      * @param integrityAlgos proposed integrity algorithms
136      */
addProposedIntegrityAlgorithm(int[] integrityAlgos)137     public void addProposedIntegrityAlgorithm(int[] integrityAlgos) {
138         for (int integrityAlgo : integrityAlgos) {
139             if (validateConfig(integrityAlgo, VALID_INTEGRITY_ALGOS, CONFIG_TYPE_INTEGRITY_ALGO)) {
140                 mProposedIntegrityAlgos.add(integrityAlgo);
141             }
142         }
143     }
144 
145     /**
146      * Add proposed encryption algorithms and respective key lengths by the carrier.
147      *
148      * @param encryptionAlgo proposed encryption algorithm
149      * @param keyLens proposed key lengths for the encryption algorithm
150      */
addProposedEncryptionAlgorithm(int encryptionAlgo, int[] keyLens)151     public void addProposedEncryptionAlgorithm(int encryptionAlgo, int[] keyLens) {
152         if (validateConfig(encryptionAlgo, VALID_ENCRYPTION_ALGOS, CONFIG_TYPE_ENCRYPT_ALGO)) {
153             for (int keyLen : keyLens) {
154                 if (validateConfig(keyLen, VALID_KEY_LENGTHS, CONFIG_TYPE_KEY_LEN)) {
155                     mProposedEncryptAlgos.add(new Pair<Integer, Integer>(encryptionAlgo, keyLen));
156                 }
157             }
158         }
159     }
160 
161     /**
162      * Add proposed AEAD algorithms and respective key lengths by the carrier.
163      *
164      * @param aeadAlgo proposed AEAD algorithm
165      * @param keyLens proposed key lengths for the encryption algorithm
166      */
addProposedAeadAlgorithm(int aeadAlgo, int[] keyLens)167     public void addProposedAeadAlgorithm(int aeadAlgo, int[] keyLens) {
168         if (validateConfig(aeadAlgo, VALID_AEAD_ALGOS, CONFIG_TYPE_AEAD_ALGO)) {
169             for (int keyLen : keyLens) {
170                 if (validateConfig(keyLen, VALID_KEY_LENGTHS, CONFIG_TYPE_KEY_LEN)) {
171                     mProposedAeadAlgos.add(new Pair<Integer, Integer>(aeadAlgo, keyLen));
172                 }
173             }
174         }
175     }
176 
177     /** Enable to reorder proposals with safer ciphers prioritized. */
enableReorderingSaferProposals()178     public void enableReorderingSaferProposals() {
179         mSaferAlgosPrioritized = true;
180     }
181 
182     /**
183      * Disable to reorder proposals with safer ciphers prioritized.Follows default configured order.
184      */
disableReorderingSaferProposals()185     public void disableReorderingSaferProposals() {
186         mSaferAlgosPrioritized = false;
187     }
188 
isSaferProposalsPrioritized()189     protected boolean isSaferProposalsPrioritized() {
190         return mSaferAlgosPrioritized;
191     }
192 
getIndexOf(Set<Integer> set, int value)193     protected int getIndexOf(Set<Integer> set, int value) {
194         Iterator<Integer> itr = set.iterator();
195         int index = 0;
196 
197         while (itr.hasNext()) {
198             if (itr.next().equals(value)) {
199                 return index;
200             }
201             index++;
202         }
203 
204         return -1;
205     }
206 
207     /** Compares the priority of the transforms. */
compareTransformPriority(Set<Integer> transformGroup, int item1, int item2)208     protected int compareTransformPriority(Set<Integer> transformGroup, int item1, int item2) {
209         return getIndexOf(transformGroup, item1) - getIndexOf(transformGroup, item2);
210     }
211 
212     /**
213      * Compares the priority of the encryption/AEAD transforms. First value in pair is
214      * encryption/AEAD algorithm and second value in pair is key length of that algorithm. If
215      * Algorithms are same then compare the priotity of the key lengths else compare the priority of
216      * the algorithms.
217      */
compareEncryptionTransformPriority( Set<Integer> algos, Set<Integer> keyLens, Pair<Integer, Integer> item1, Pair<Integer, Integer> item2)218     protected int compareEncryptionTransformPriority(
219             Set<Integer> algos,
220             Set<Integer> keyLens,
221             Pair<Integer, Integer> item1,
222             Pair<Integer, Integer> item2) {
223         return item1.first.equals(item2.first)
224                 ? getIndexOf(keyLens, item1.second) - getIndexOf(keyLens, item2.second)
225                 : getIndexOf(algos, item1.first) - getIndexOf(algos, item2.first);
226     }
227 
getDhGroups()228     protected int[] getDhGroups() {
229         if (isSaferProposalsPrioritized()) {
230             return mProposedDhGroups.stream()
231                     .sorted(
232                             (item1, item2) ->
233                                     compareTransformPriority(VALID_DH_GROUPS, item1, item2))
234                     .mapToInt(Integer::intValue)
235                     .toArray();
236         }
237 
238         return mProposedDhGroups.stream().mapToInt(Integer::intValue).toArray();
239     }
240 
getSupportedDhGroups()241     protected int[] getSupportedDhGroups() {
242         return VALID_DH_GROUPS.stream().mapToInt(Integer::intValue).toArray();
243     }
244 
getIntegrityAlgos()245     protected int[] getIntegrityAlgos() {
246         if (isSaferProposalsPrioritized()) {
247             return mProposedIntegrityAlgos.stream()
248                     .sorted(
249                             (item1, item2) ->
250                                     compareTransformPriority(VALID_INTEGRITY_ALGOS, item1, item2))
251                     .mapToInt(Integer::intValue)
252                     .toArray();
253         }
254 
255         return mProposedIntegrityAlgos.stream().mapToInt(Integer::intValue).toArray();
256     }
257 
getSupportedIntegrityAlgos()258     protected int[] getSupportedIntegrityAlgos() {
259         return VALID_INTEGRITY_ALGOS.stream().mapToInt(Integer::intValue).toArray();
260     }
261 
getEncryptionAlgos()262     protected Pair<Integer, Integer>[] getEncryptionAlgos() {
263         if (isSaferProposalsPrioritized()) {
264             return mProposedEncryptAlgos.stream()
265                     .sorted(
266                             (item1, item2) ->
267                                     compareEncryptionTransformPriority(
268                                             VALID_ENCRYPTION_ALGOS,
269                                             VALID_KEY_LENGTHS,
270                                             item1,
271                                             item2))
272                     .toArray(Pair[]::new);
273         }
274 
275         return mProposedEncryptAlgos.toArray(new Pair[mProposedEncryptAlgos.size()]);
276     }
277 
getSupportedEncryptionAlgos()278     protected Pair<Integer, Integer>[] getSupportedEncryptionAlgos() {
279         Pair<Integer, Integer>[] encrAlgos =
280                 new Pair[VALID_ENCRYPTION_ALGOS.size() * VALID_KEY_LENGTHS.size()];
281         int index = 0;
282         for (int algo : VALID_ENCRYPTION_ALGOS) {
283             for (int len : VALID_KEY_LENGTHS) {
284                 encrAlgos[index++] = new Pair(algo, len);
285             }
286         }
287 
288         return encrAlgos;
289     }
290 
getAeadAlgos()291     protected Pair<Integer, Integer>[] getAeadAlgos() {
292         if (isSaferProposalsPrioritized()) {
293             return mProposedAeadAlgos.stream()
294                     .sorted(
295                             (item1, item2) ->
296                                     compareEncryptionTransformPriority(
297                                             VALID_AEAD_ALGOS, VALID_KEY_LENGTHS, item1, item2))
298                     .toArray(Pair[]::new);
299         }
300 
301         return mProposedAeadAlgos.toArray(new Pair[mProposedAeadAlgos.size()]);
302     }
303 
getSupportedAeadAlgos()304     protected Pair<Integer, Integer>[] getSupportedAeadAlgos() {
305         Pair<Integer, Integer>[] aeadAlgos =
306                 new Pair[VALID_AEAD_ALGOS.size() * VALID_KEY_LENGTHS.size()];
307         int index = 0;
308         for (int algo : VALID_AEAD_ALGOS) {
309             for (int len : VALID_KEY_LENGTHS) {
310                 aeadAlgos[index++] = new Pair(algo, len);
311             }
312         }
313 
314         return aeadAlgos;
315     }
316 
validateConfig( int config, Set<Integer> validConfigValues, String configType)317     protected static boolean validateConfig(
318             int config, Set<Integer> validConfigValues, String configType) {
319         if (validConfigValues.contains(config)) {
320             return true;
321         }
322 
323         Log.e(TAG, "Invalid config value for " + configType + ":" + config);
324         return false;
325     }
326 }
327