/* * 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. * *

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. * *

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. * *

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 * *

@see {@link * TunnelModeChildSessionParams.Builder#addInboundTrafficSelectors(IkeTrafficSelector)} or * {@link * TransportModeChildSessionParams.Builder#addInboundTrafficSelectors(IkeTrafficSelector)} */ @NonNull public List getInboundTrafficSelectors() { return Arrays.asList(mInboundTrafficSelectors); } /** * Retrieves configured outbound traffic selectors * *

@see {@link * TunnelModeChildSessionParams.Builder#addOutboundTrafficSelectors(IkeTrafficSelector)} or * {@link * TransportModeChildSessionParams.Builder#addOutboundTrafficSelectors(IkeTrafficSelector)} */ @NonNull public List getOutboundTrafficSelectors() { return Arrays.asList(mOutboundTrafficSelectors); } /** Retrieves all ChildSaProposals configured */ @NonNull public List 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 mInboundTsList = new LinkedList<>(); @NonNull protected final List mOutboundTsList = new LinkedList<>(); @NonNull protected final List 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); } }