blob: 0221491c1d3b2ba081d4c20cdce7a05d8dc06d7a [file] [log] [blame]
/*
* Copyright (C) 2019 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.ipsec.ike;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.net.InetAddresses;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* ChildSessionParams is an abstract class that represents proposed configurations for negotiating a
* Child Session.
*
* <p>Note that references to negotiated configurations will be held, and the same parameters will
* be reused during rekey. This includes SA Proposals, lifetimes and traffic selectors.
*
* <p>IKE library will send out KE payload only if user has configured one or more DH groups. The KE
* payload in a request will use the first DH group from the first user provided SA proposal (or the
* peer selected SA proposal if it's a rekey request). The KE payload in a response will depend on
* the SA proposal negotiation result.
*
* <p>When requesting the first Child Session in IKE AUTH, IKE library will not propose any DH group
* even if user has configured it, as per RFC 7296. When rekeying this child session, IKE library
* will accept DH groups that are configured in its ChildSessionParams. If after rekeying user needs
* to have the same DH group as that of the IKE Session, then they need to explicitly set the same
* DH Group in ChildSessionParams.
*
* @see {@link TunnelModeChildSessionParams} and {@link TransportModeChildSessionParams}
* @hide
*/
@SystemApi
public abstract class ChildSessionParams {
/** @hide */
protected static final int CHILD_HARD_LIFETIME_SEC_MINIMUM = 300; // 5 minutes
/** @hide */
protected static final int CHILD_HARD_LIFETIME_SEC_MAXIMUM = 14400; // 4 hours
/** @hide */
protected static final int CHILD_HARD_LIFETIME_SEC_DEFAULT = 7200; // 2 hours
/** @hide */
protected static final int CHILD_SOFT_LIFETIME_SEC_MINIMUM = 120; // 2 minutes
/** @hide */
protected static final int CHILD_SOFT_LIFETIME_SEC_DEFAULT = 3600; // 1 hour
/** @hide */
protected static final int CHILD_LIFETIME_MARGIN_SEC_MINIMUM =
(int) TimeUnit.MINUTES.toSeconds(1L);
@NonNull private static final IkeTrafficSelector DEFAULT_TRAFFIC_SELECTOR_IPV4;
@NonNull private static final IkeTrafficSelector DEFAULT_TRAFFIC_SELECTOR_IPV6;
static {
DEFAULT_TRAFFIC_SELECTOR_IPV4 =
buildDefaultTrafficSelector(
IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE);
DEFAULT_TRAFFIC_SELECTOR_IPV6 =
buildDefaultTrafficSelector(
IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE);
}
@NonNull private final IkeTrafficSelector[] mInboundTrafficSelectors;
@NonNull private final IkeTrafficSelector[] mOutboundTrafficSelectors;
@NonNull private final ChildSaProposal[] mSaProposals;
private final int mHardLifetimeSec;
private final int mSoftLifetimeSec;
private final boolean mIsTransport;
/** @hide */
protected ChildSessionParams(
IkeTrafficSelector[] inboundTs,
IkeTrafficSelector[] outboundTs,
ChildSaProposal[] proposals,
int hardLifetimeSec,
int softLifetimeSec,
boolean isTransport) {
mInboundTrafficSelectors = inboundTs;
mOutboundTrafficSelectors = outboundTs;
mSaProposals = proposals;
mHardLifetimeSec = hardLifetimeSec;
mSoftLifetimeSec = softLifetimeSec;
mIsTransport = isTransport;
}
/**
* Retrieves configured inbound traffic selectors
*
* <p>@see {@link
* TunnelModeChildSessionParams.Builder#addInboundTrafficSelectors(IkeTrafficSelector)} or
* {@link
* TransportModeChildSessionParams.Builder#addInboundTrafficSelectors(IkeTrafficSelector)}
*/
@NonNull
public List<IkeTrafficSelector> getInboundTrafficSelectors() {
return Arrays.asList(mInboundTrafficSelectors);
}
/**
* Retrieves configured outbound traffic selectors
*
* <p>@see {@link
* TunnelModeChildSessionParams.Builder#addOutboundTrafficSelectors(IkeTrafficSelector)} or
* {@link
* TransportModeChildSessionParams.Builder#addOutboundTrafficSelectors(IkeTrafficSelector)}
*/
@NonNull
public List<IkeTrafficSelector> getOutboundTrafficSelectors() {
return Arrays.asList(mOutboundTrafficSelectors);
}
/** Retrieves all ChildSaProposals configured */
@NonNull
public List<ChildSaProposal> getSaProposals() {
return Arrays.asList(mSaProposals);
}
/** Retrieves hard lifetime in seconds */
// Use "second" because smaller unit won't make sense to describe a rekey interval.
@SuppressLint("MethodNameUnits")
@IntRange(from = CHILD_HARD_LIFETIME_SEC_MINIMUM, to = CHILD_HARD_LIFETIME_SEC_MAXIMUM)
public int getHardLifetimeSeconds() {
return mHardLifetimeSec;
}
/** Retrieves soft lifetime in seconds */
// Use "second" because smaller unit won't make sense to describe a rekey interval.
@SuppressLint("MethodNameUnits")
@IntRange(from = CHILD_SOFT_LIFETIME_SEC_MINIMUM, to = CHILD_HARD_LIFETIME_SEC_MAXIMUM)
public int getSoftLifetimeSeconds() {
return mSoftLifetimeSec;
}
/** @hide */
public IkeTrafficSelector[] getInboundTrafficSelectorsInternal() {
return mInboundTrafficSelectors;
}
/** @hide */
public IkeTrafficSelector[] getOutboundTrafficSelectorsInternal() {
return mOutboundTrafficSelectors;
}
/** @hide */
public ChildSaProposal[] getSaProposalsInternal() {
return mSaProposals;
}
/** @hide */
public long getHardLifetimeMsInternal() {
return TimeUnit.SECONDS.toMillis((long) mHardLifetimeSec);
}
/** @hide */
public long getSoftLifetimeMsInternal() {
return TimeUnit.SECONDS.toMillis((long) mSoftLifetimeSec);
}
/** @hide */
public boolean isTransportMode() {
return mIsTransport;
}
/**
* This class represents common information for Child Session Parameters Builders.
*
* @hide
*/
protected abstract static class Builder {
@NonNull protected final List<IkeTrafficSelector> mInboundTsList = new LinkedList<>();
@NonNull protected final List<IkeTrafficSelector> mOutboundTsList = new LinkedList<>();
@NonNull protected final List<SaProposal> mSaProposalList = new LinkedList<>();
protected int mHardLifetimeSec = CHILD_HARD_LIFETIME_SEC_DEFAULT;
protected int mSoftLifetimeSec = CHILD_SOFT_LIFETIME_SEC_DEFAULT;
protected void addProposal(@NonNull ChildSaProposal proposal) {
mSaProposalList.add(proposal);
}
protected void addInboundTs(@NonNull IkeTrafficSelector trafficSelector) {
mInboundTsList.add(trafficSelector);
}
protected void addOutboundTs(@NonNull IkeTrafficSelector trafficSelector) {
mOutboundTsList.add(trafficSelector);
}
protected void validateAndSetLifetime(int hardLifetimeSec, int softLifetimeSec) {
if (hardLifetimeSec < CHILD_HARD_LIFETIME_SEC_MINIMUM
|| hardLifetimeSec > CHILD_HARD_LIFETIME_SEC_MAXIMUM
|| softLifetimeSec < CHILD_SOFT_LIFETIME_SEC_MINIMUM
|| hardLifetimeSec - softLifetimeSec < CHILD_LIFETIME_MARGIN_SEC_MINIMUM) {
throw new IllegalArgumentException("Invalid lifetime value");
}
}
protected void validateOrThrow() {
if (mSaProposalList.isEmpty()) {
throw new IllegalArgumentException(
"ChildSessionParams requires at least one Child SA proposal.");
}
}
protected void addDefaultTsIfNotConfigured() {
if (mInboundTsList.isEmpty()) {
mInboundTsList.add(DEFAULT_TRAFFIC_SELECTOR_IPV4);
mInboundTsList.add(DEFAULT_TRAFFIC_SELECTOR_IPV6);
}
if (mOutboundTsList.isEmpty()) {
mOutboundTsList.add(DEFAULT_TRAFFIC_SELECTOR_IPV4);
mOutboundTsList.add(DEFAULT_TRAFFIC_SELECTOR_IPV6);
}
}
}
private static IkeTrafficSelector buildDefaultTrafficSelector(
@IkeTrafficSelector.TrafficSelectorType int tsType) {
int startPort = IkeTrafficSelector.PORT_NUMBER_MIN;
int endPort = IkeTrafficSelector.PORT_NUMBER_MAX;
InetAddress startAddress = null;
InetAddress endAddress = null;
switch (tsType) {
case IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV4_ADDR_RANGE:
startAddress = InetAddresses.parseNumericAddress("0.0.0.0");
endAddress = InetAddresses.parseNumericAddress("255.255.255.255");
break;
case IkeTrafficSelector.TRAFFIC_SELECTOR_TYPE_IPV6_ADDR_RANGE:
startAddress = InetAddresses.parseNumericAddress("::");
endAddress =
InetAddresses.parseNumericAddress(
"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
break;
default:
throw new IllegalArgumentException("Invalid Traffic Selector type: " + tsType);
}
return new IkeTrafficSelector(tsType, startPort, endPort, startAddress, endAddress);
}
}