• 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 com.android.server.vcn.util;
18 
19 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_3DES;
20 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC;
21 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CTR;
22 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
23 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16;
24 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8;
25 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_CHACHA20_POLY1305;
26 import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_CMAC_96;
27 import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96;
28 import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96;
29 import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128;
30 import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192;
31 import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256;
32 import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_NONE;
33 
34 import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
35 
36 import static java.lang.Math.max;
37 import static java.util.Collections.unmodifiableMap;
38 
39 import android.annotation.NonNull;
40 import android.net.ipsec.ike.ChildSaProposal;
41 import android.util.ArrayMap;
42 import android.util.Pair;
43 import android.util.Slog;
44 
45 import java.util.List;
46 import java.util.Map;
47 
48 /** @hide */
49 public class MtuUtils {
50     private static final String TAG = MtuUtils.class.getSimpleName();
51     /**
52      * Max ESP overhead possible
53      *
54      * <p>60 (Outer IPv4 + options) + 8 (UDP encap) + 4 (SPI) + 4 (Seq) + 2 (Pad + NextHeader)
55      */
56     private static final int GENERIC_ESP_OVERHEAD_MAX = 78;
57 
58     /** Maximum overheads of authentication algorithms, keyed on IANA-defined constants */
59     private static final Map<Integer, Integer> AUTH_ALGORITHM_OVERHEAD;
60 
61     static {
62         final Map<Integer, Integer> map = new ArrayMap<>();
map.put(INTEGRITY_ALGORITHM_NONE, 0)63         map.put(INTEGRITY_ALGORITHM_NONE, 0);
map.put(INTEGRITY_ALGORITHM_HMAC_SHA1_96, 12)64         map.put(INTEGRITY_ALGORITHM_HMAC_SHA1_96, 12);
map.put(INTEGRITY_ALGORITHM_AES_XCBC_96, 12)65         map.put(INTEGRITY_ALGORITHM_AES_XCBC_96, 12);
map.put(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128, 32)66         map.put(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128, 32);
map.put(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192, 48)67         map.put(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192, 48);
map.put(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256, 64)68         map.put(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256, 64);
map.put(INTEGRITY_ALGORITHM_AES_CMAC_96, 12)69         map.put(INTEGRITY_ALGORITHM_AES_CMAC_96, 12);
70 
71         AUTH_ALGORITHM_OVERHEAD = unmodifiableMap(map);
72     }
73 
74     /** Maximum overheads of encryption algorithms, keyed on IANA-defined constants */
75     private static final Map<Integer, Integer> CRYPT_ALGORITHM_OVERHEAD;
76 
77     static {
78         final Map<Integer, Integer> map = new ArrayMap<>();
map.put(ENCRYPTION_ALGORITHM_3DES, 15)79         map.put(ENCRYPTION_ALGORITHM_3DES, 15); // 8 (IV) + 7 (Max pad)
map.put(ENCRYPTION_ALGORITHM_AES_CBC, 31)80         map.put(ENCRYPTION_ALGORITHM_AES_CBC, 31); // 16 (IV) + 15 (Max pad)
map.put(ENCRYPTION_ALGORITHM_AES_CTR, 11)81         map.put(ENCRYPTION_ALGORITHM_AES_CTR, 11); // 8 (IV) + 3 (Max pad)
82 
83         CRYPT_ALGORITHM_OVERHEAD = unmodifiableMap(map);
84     }
85 
86     /** Maximum overheads of combined mode algorithms, keyed on IANA-defined constants */
87     private static final Map<Integer, Integer> AUTHCRYPT_ALGORITHM_OVERHEAD;
88 
89     static {
90         final Map<Integer, Integer> map = new ArrayMap<>();
map.put(ENCRYPTION_ALGORITHM_AES_GCM_8, 19)91         map.put(ENCRYPTION_ALGORITHM_AES_GCM_8, 19); // 8 (IV) + 3 (Max pad) + 8 (ICV)
map.put(ENCRYPTION_ALGORITHM_AES_GCM_12, 23)92         map.put(ENCRYPTION_ALGORITHM_AES_GCM_12, 23); // 8 (IV) + 3 (Max pad) + 12 (ICV)
map.put(ENCRYPTION_ALGORITHM_AES_GCM_16, 27)93         map.put(ENCRYPTION_ALGORITHM_AES_GCM_16, 27); // 8 (IV) + 3 (Max pad) + 16 (ICV)
map.put(ENCRYPTION_ALGORITHM_CHACHA20_POLY1305, 27)94         map.put(ENCRYPTION_ALGORITHM_CHACHA20_POLY1305, 27); // 8 (IV) + 3 (Max pad) + 16 (ICV)
95 
96         AUTHCRYPT_ALGORITHM_OVERHEAD = unmodifiableMap(map);
97     }
98 
99     /**
100      * Calculates the MTU of the inner interface based on the parameters provided
101      *
102      * <p>The MTU of the inner interface will be the minimum of the following:
103      *
104      * <ul>
105      *   <li>The MTU of the outer interface, minus the greatest ESP overhead (based on proposed
106      *       algorithms).
107      *   <li>The maximum MTU as provided in the arguments.
108      * </ul>
109      */
getMtu( @onNull List<ChildSaProposal> childProposals, int maxMtu, int underlyingMtu)110     public static int getMtu(
111             @NonNull List<ChildSaProposal> childProposals, int maxMtu, int underlyingMtu) {
112         if (underlyingMtu <= 0) {
113             return IPV6_MIN_MTU;
114         }
115 
116         int maxAuthOverhead = 0;
117         int maxCryptOverhead = 0;
118         int maxAuthCryptOverhead = 0;
119 
120         for (ChildSaProposal proposal : childProposals) {
121             for (Pair<Integer, Integer> encryptionAlgoPair : proposal.getEncryptionAlgorithms()) {
122                 final int algo = encryptionAlgoPair.first;
123 
124                 if (AUTHCRYPT_ALGORITHM_OVERHEAD.containsKey(algo)) {
125                     maxAuthCryptOverhead =
126                             max(maxAuthCryptOverhead, AUTHCRYPT_ALGORITHM_OVERHEAD.get(algo));
127                     continue;
128                 } else if (CRYPT_ALGORITHM_OVERHEAD.containsKey(algo)) {
129                     maxCryptOverhead = max(maxCryptOverhead, CRYPT_ALGORITHM_OVERHEAD.get(algo));
130                     continue;
131                 }
132 
133                 Slog.wtf(TAG, "Unknown encryption algorithm requested: " + algo);
134                 return IPV6_MIN_MTU;
135             }
136 
137             for (int algo : proposal.getIntegrityAlgorithms()) {
138                 if (AUTH_ALGORITHM_OVERHEAD.containsKey(algo)) {
139                     maxAuthOverhead = max(maxAuthOverhead, AUTH_ALGORITHM_OVERHEAD.get(algo));
140                     continue;
141                 }
142 
143                 Slog.wtf(TAG, "Unknown integrity algorithm requested: " + algo);
144                 return IPV6_MIN_MTU;
145             }
146         }
147 
148         // Return minimum of maxMtu, and the adjusted MTUs based on algorithms.
149         final int combinedModeMtu = underlyingMtu - maxAuthCryptOverhead - GENERIC_ESP_OVERHEAD_MAX;
150         final int normalModeMtu =
151                 underlyingMtu - maxCryptOverhead - maxAuthOverhead - GENERIC_ESP_OVERHEAD_MAX;
152         return Math.min(Math.min(maxMtu, combinedModeMtu), normalModeMtu);
153     }
154 }
155