1 /* 2 * Copyright (C) 2019 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.ipsec.ike; 18 19 import android.annotation.IntRange; 20 import android.annotation.NonNull; 21 import android.annotation.SuppressLint; 22 import android.annotation.SystemApi; 23 import android.net.InetAddresses; 24 25 import java.net.InetAddress; 26 import java.util.Arrays; 27 import java.util.LinkedList; 28 import java.util.List; 29 import java.util.concurrent.TimeUnit; 30 31 /** 32 * ChildSessionParams is an abstract class that represents proposed configurations for negotiating a 33 * Child Session. 34 * 35 * <p>Note that references to negotiated configurations will be held, and the same parameters will 36 * be reused during rekey. This includes SA Proposals, lifetimes and traffic selectors. 37 * 38 * <p>IKE library will send out KE payload only if user has configured one or more DH groups. The KE 39 * payload in a request will use the first DH group from the first user provided SA proposal (or the 40 * peer selected SA proposal if it's a rekey request). The KE payload in a response will depend on 41 * the SA proposal negotiation result. 42 * 43 * <p>When requesting the first Child Session in IKE AUTH, IKE library will not propose any DH group 44 * even if user has configured it, as per RFC 7296. When rekeying this child session, IKE library 45 * will accept DH groups that are configured in its ChildSessionParams. If after rekeying user needs 46 * to have the same DH group as that of the IKE Session, then they need to explicitly set the same 47 * DH Group in ChildSessionParams. 48 * 49 * @see {@link TunnelModeChildSessionParams} and {@link TransportModeChildSessionParams} 50 * @hide 51 */ 52 @SystemApi 53 public abstract class ChildSessionParams { 54 /** @hide */ 55 protected static final int CHILD_HARD_LIFETIME_SEC_MINIMUM = 300; // 5 minutes 56 /** @hide */ 57 protected static final int CHILD_HARD_LIFETIME_SEC_MAXIMUM = 14400; // 4 hours 58 /** @hide */ 59 protected static final int CHILD_HARD_LIFETIME_SEC_DEFAULT = 7200; // 2 hours 60 61 /** @hide */ 62 protected static final int CHILD_SOFT_LIFETIME_SEC_MINIMUM = 120; // 2 minutes 63 /** @hide */ 64 protected static final int CHILD_SOFT_LIFETIME_SEC_DEFAULT = 3600; // 1 hour 65 66 /** @hide */ 67 protected static final int CHILD_LIFETIME_MARGIN_SEC_MINIMUM = 68 (int) TimeUnit.MINUTES.toSeconds(1L); 69 70 @NonNull private static final IkeTrafficSelector DEFAULT_TRAFFIC_SELECTOR_IPV4; 71 @NonNull private static final IkeTrafficSelector DEFAULT_TRAFFIC_SELECTOR_IPV6; 72 73 static { 74 DEFAULT_TRAFFIC_SELECTOR_IPV4 = 75 buildDefaultTrafficSelector( 76 IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE); 77 DEFAULT_TRAFFIC_SELECTOR_IPV6 = 78 buildDefaultTrafficSelector( 79 IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE); 80 } 81 82 @NonNull private final IkeTrafficSelector[] mInboundTrafficSelectors; 83 @NonNull private final IkeTrafficSelector[] mOutboundTrafficSelectors; 84 @NonNull private final ChildSaProposal[] mSaProposals; 85 86 private final int mHardLifetimeSec; 87 private final int mSoftLifetimeSec; 88 89 private final boolean mIsTransport; 90 91 /** @hide */ ChildSessionParams( IkeTrafficSelector[] inboundTs, IkeTrafficSelector[] outboundTs, ChildSaProposal[] proposals, int hardLifetimeSec, int softLifetimeSec, boolean isTransport)92 protected ChildSessionParams( 93 IkeTrafficSelector[] inboundTs, 94 IkeTrafficSelector[] outboundTs, 95 ChildSaProposal[] proposals, 96 int hardLifetimeSec, 97 int softLifetimeSec, 98 boolean isTransport) { 99 mInboundTrafficSelectors = inboundTs; 100 mOutboundTrafficSelectors = outboundTs; 101 mSaProposals = proposals; 102 mHardLifetimeSec = hardLifetimeSec; 103 mSoftLifetimeSec = softLifetimeSec; 104 mIsTransport = isTransport; 105 } 106 107 /** 108 * Retrieves configured inbound traffic selectors 109 * 110 * <p>@see {@link 111 * TunnelModeChildSessionParams.Builder#addInboundTrafficSelectors(IkeTrafficSelector)} or 112 * {@link 113 * TransportModeChildSessionParams.Builder#addInboundTrafficSelectors(IkeTrafficSelector)} 114 */ 115 @NonNull getInboundTrafficSelectors()116 public List<IkeTrafficSelector> getInboundTrafficSelectors() { 117 return Arrays.asList(mInboundTrafficSelectors); 118 } 119 120 /** 121 * Retrieves configured outbound traffic selectors 122 * 123 * <p>@see {@link 124 * TunnelModeChildSessionParams.Builder#addOutboundTrafficSelectors(IkeTrafficSelector)} or 125 * {@link 126 * TransportModeChildSessionParams.Builder#addOutboundTrafficSelectors(IkeTrafficSelector)} 127 */ 128 @NonNull getOutboundTrafficSelectors()129 public List<IkeTrafficSelector> getOutboundTrafficSelectors() { 130 return Arrays.asList(mOutboundTrafficSelectors); 131 } 132 133 /** Retrieves all ChildSaProposals configured */ 134 @NonNull getSaProposals()135 public List<ChildSaProposal> getSaProposals() { 136 return Arrays.asList(mSaProposals); 137 } 138 139 /** Retrieves hard lifetime in seconds */ 140 // Use "second" because smaller unit won't make sense to describe a rekey interval. 141 @SuppressLint("MethodNameUnits") 142 @IntRange(from = CHILD_HARD_LIFETIME_SEC_MINIMUM, to = CHILD_HARD_LIFETIME_SEC_MAXIMUM) getHardLifetimeSeconds()143 public int getHardLifetimeSeconds() { 144 return mHardLifetimeSec; 145 } 146 147 /** Retrieves soft lifetime in seconds */ 148 // Use "second" because smaller unit won't make sense to describe a rekey interval. 149 @SuppressLint("MethodNameUnits") 150 @IntRange(from = CHILD_SOFT_LIFETIME_SEC_MINIMUM, to = CHILD_HARD_LIFETIME_SEC_MAXIMUM) getSoftLifetimeSeconds()151 public int getSoftLifetimeSeconds() { 152 return mSoftLifetimeSec; 153 } 154 155 /** @hide */ getInboundTrafficSelectorsInternal()156 public IkeTrafficSelector[] getInboundTrafficSelectorsInternal() { 157 return mInboundTrafficSelectors; 158 } 159 160 /** @hide */ getOutboundTrafficSelectorsInternal()161 public IkeTrafficSelector[] getOutboundTrafficSelectorsInternal() { 162 return mOutboundTrafficSelectors; 163 } 164 165 /** @hide */ getSaProposalsInternal()166 public ChildSaProposal[] getSaProposalsInternal() { 167 return mSaProposals; 168 } 169 170 /** @hide */ getHardLifetimeMsInternal()171 public long getHardLifetimeMsInternal() { 172 return TimeUnit.SECONDS.toMillis((long) mHardLifetimeSec); 173 } 174 175 /** @hide */ getSoftLifetimeMsInternal()176 public long getSoftLifetimeMsInternal() { 177 return TimeUnit.SECONDS.toMillis((long) mSoftLifetimeSec); 178 } 179 180 /** @hide */ isTransportMode()181 public boolean isTransportMode() { 182 return mIsTransport; 183 } 184 185 /** 186 * This class represents common information for Child Session Parameters Builders. 187 * 188 * @hide 189 */ 190 protected abstract static class Builder { 191 @NonNull protected final List<IkeTrafficSelector> mInboundTsList = new LinkedList<>(); 192 @NonNull protected final List<IkeTrafficSelector> mOutboundTsList = new LinkedList<>(); 193 @NonNull protected final List<SaProposal> mSaProposalList = new LinkedList<>(); 194 195 protected int mHardLifetimeSec = CHILD_HARD_LIFETIME_SEC_DEFAULT; 196 protected int mSoftLifetimeSec = CHILD_SOFT_LIFETIME_SEC_DEFAULT; 197 addProposal(@onNull ChildSaProposal proposal)198 protected void addProposal(@NonNull ChildSaProposal proposal) { 199 mSaProposalList.add(proposal); 200 } 201 addInboundTs(@onNull IkeTrafficSelector trafficSelector)202 protected void addInboundTs(@NonNull IkeTrafficSelector trafficSelector) { 203 mInboundTsList.add(trafficSelector); 204 } 205 addOutboundTs(@onNull IkeTrafficSelector trafficSelector)206 protected void addOutboundTs(@NonNull IkeTrafficSelector trafficSelector) { 207 mOutboundTsList.add(trafficSelector); 208 } 209 validateAndSetLifetime(int hardLifetimeSec, int softLifetimeSec)210 protected void validateAndSetLifetime(int hardLifetimeSec, int softLifetimeSec) { 211 if (hardLifetimeSec < CHILD_HARD_LIFETIME_SEC_MINIMUM 212 || hardLifetimeSec > CHILD_HARD_LIFETIME_SEC_MAXIMUM 213 || softLifetimeSec < CHILD_SOFT_LIFETIME_SEC_MINIMUM 214 || hardLifetimeSec - softLifetimeSec < CHILD_LIFETIME_MARGIN_SEC_MINIMUM) { 215 throw new IllegalArgumentException("Invalid lifetime value"); 216 } 217 } 218 validateOrThrow()219 protected void validateOrThrow() { 220 if (mSaProposalList.isEmpty()) { 221 throw new IllegalArgumentException( 222 "ChildSessionParams requires at least one Child SA proposal."); 223 } 224 } 225 addDefaultTsIfNotConfigured()226 protected void addDefaultTsIfNotConfigured() { 227 if (mInboundTsList.isEmpty()) { 228 mInboundTsList.add(DEFAULT_TRAFFIC_SELECTOR_IPV4); 229 mInboundTsList.add(DEFAULT_TRAFFIC_SELECTOR_IPV6); 230 } 231 232 if (mOutboundTsList.isEmpty()) { 233 mOutboundTsList.add(DEFAULT_TRAFFIC_SELECTOR_IPV4); 234 mOutboundTsList.add(DEFAULT_TRAFFIC_SELECTOR_IPV6); 235 } 236 } 237 } 238 buildDefaultTrafficSelector( @keTrafficSelector.TrafficSelectorType int tsType)239 private static IkeTrafficSelector buildDefaultTrafficSelector( 240 @IkeTrafficSelector.TrafficSelectorType int tsType) { 241 int startPort = IkeTrafficSelector.PORT_NUMBER_MIN; 242 int endPort = IkeTrafficSelector.PORT_NUMBER_MAX; 243 InetAddress startAddress = null; 244 InetAddress endAddress = null; 245 switch (tsType) { 246 case IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE: 247 startAddress = InetAddresses.parseNumericAddress("0.0.0.0"); 248 endAddress = InetAddresses.parseNumericAddress("255.255.255.255"); 249 break; 250 case IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE: 251 startAddress = InetAddresses.parseNumericAddress("::"); 252 endAddress = 253 InetAddresses.parseNumericAddress( 254 "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); 255 break; 256 default: 257 throw new IllegalArgumentException("Invalid Traffic Selector type: " + tsType); 258 } 259 260 return new IkeTrafficSelector(tsType, startPort, endPort, startAddress, endAddress); 261 } 262 } 263