Javadoc cleanup of IpSecManager API.

This changes only comments and annotations, which results
in minor API changes.

Bug: 63777932
Test: `make update-api` and visually inspect generated HTML.
Change-Id: I7a7a9244eade6cc55aca17a47e0a838cd6f84cc9
This commit is contained in:
Jonathan Basseri
2017-04-21 15:53:51 -07:00
parent 28dc8a29a1
commit 2725a233c9
4 changed files with 299 additions and 222 deletions

View File

@@ -15,6 +15,7 @@
*/ */
package android.net; package android.net;
import android.annotation.NonNull;
import android.annotation.StringDef; import android.annotation.StringDef;
import android.os.Build; import android.os.Build;
import android.os.Parcel; import android.os.Parcel;
@@ -27,8 +28,10 @@ import java.lang.annotation.RetentionPolicy;
import java.util.Arrays; import java.util.Arrays;
/** /**
* IpSecAlgorithm specifies a single algorithm that can be applied to an IpSec Transform. Refer to * This class represents a single algorithm that can be used by an {@link IpSecTransform}.
* RFC 4301. *
* @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
* Internet Protocol</a>
*/ */
public final class IpSecAlgorithm implements Parcelable { public final class IpSecAlgorithm implements Parcelable {
/** /**
@@ -39,16 +42,16 @@ public final class IpSecAlgorithm implements Parcelable {
public static final String CRYPT_AES_CBC = "cbc(aes)"; public static final String CRYPT_AES_CBC = "cbc(aes)";
/** /**
* MD5 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in new * MD5 HMAC Authentication/Integrity Algorithm. <b>This algorithm is not recommended for use in
* applications and is provided for legacy compatibility with 3gpp infrastructure. * new applications and is provided for legacy compatibility with 3gpp infrastructure.</b>
* *
* <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 128. * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 128.
*/ */
public static final String AUTH_HMAC_MD5 = "hmac(md5)"; public static final String AUTH_HMAC_MD5 = "hmac(md5)";
/** /**
* SHA1 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in * SHA1 HMAC Authentication/Integrity Algorithm. <b>This algorithm is not recommended for use in
* new applications and is provided for legacy compatibility with 3gpp infrastructure. * new applications and is provided for legacy compatibility with 3gpp infrastructure.</b>
* *
* <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 160. * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 160.
*/ */
@@ -69,7 +72,7 @@ public final class IpSecAlgorithm implements Parcelable {
public static final String AUTH_HMAC_SHA384 = "hmac(sha384)"; public static final String AUTH_HMAC_SHA384 = "hmac(sha384)";
/** /**
* SHA512 HMAC Authentication/Integrity Algorithm * SHA512 HMAC Authentication/Integrity Algorithm.
* *
* <p>Valid truncation lengths are multiples of 8 bits from 256 to (default) 512. * <p>Valid truncation lengths are multiples of 8 bits from 256 to (default) 512.
*/ */
@@ -80,9 +83,9 @@ public final class IpSecAlgorithm implements Parcelable {
* *
* <p>Valid lengths for keying material are {160, 224, 288}. * <p>Valid lengths for keying material are {160, 224, 288}.
* *
* <p>As per RFC4106 (Section 8.1), keying material consists of a 128, 192, or 256 bit AES key * <p>As per <a href="https://tools.ietf.org/html/rfc4106#section-8.1">RFC4106 (Section
* followed by a 32-bit salt. RFC compliance requires that the salt must be unique per * 8.1)</a>, keying material consists of a 128, 192, or 256 bit AES key followed by a 32-bit
* invocation with the same key. * salt. RFC compliance requires that the salt must be unique per invocation with the same key.
* *
* <p>Valid ICV (truncation) lengths are {64, 96, 128}. * <p>Valid ICV (truncation) lengths are {64, 96, 128}.
*/ */
@@ -105,48 +108,47 @@ public final class IpSecAlgorithm implements Parcelable {
private final int mTruncLenBits; private final int mTruncLenBits;
/** /**
* Specify a IpSecAlgorithm of one of the supported types including the truncation length of the * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are
* algorithm * defined as constants in this class.
* *
* @param algorithm type for IpSec. * @param algorithm name of the algorithm.
* @param key non-null Key padded to a multiple of 8 bits. * @param key key padded to a multiple of 8 bits.
*/ */
public IpSecAlgorithm(String algorithm, byte[] key) { public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key) {
this(algorithm, key, key.length * 8); this(algorithm, key, key.length * 8);
} }
/** /**
* Specify a IpSecAlgorithm of one of the supported types including the truncation length of the * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are
* algorithm * defined as constants in this class.
* *
* @param algoName precise name of the algorithm to be used. * <p>This constructor only supports algorithms that use a truncation length. i.e.
* @param key non-null Key padded to a multiple of 8 bits. * Authentication and Authenticated Encryption algorithms.
* @param truncLenBits the number of bits of output hash to use; only meaningful for *
* Authentication or Authenticated Encryption (equivalent to ICV length). * @param algorithm name of the algorithm.
* @param key key padded to a multiple of 8 bits.
* @param truncLenBits number of bits of output hash to use.
*/ */
public IpSecAlgorithm(@AlgorithmName String algoName, byte[] key, int truncLenBits) { public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) {
if (!isTruncationLengthValid(algoName, truncLenBits)) { if (!isTruncationLengthValid(algorithm, truncLenBits)) {
throw new IllegalArgumentException("Unknown algorithm or invalid length"); throw new IllegalArgumentException("Unknown algorithm or invalid length");
} }
mName = algoName; mName = algorithm;
mKey = key.clone(); mKey = key.clone();
mTruncLenBits = Math.min(truncLenBits, key.length * 8); mTruncLenBits = Math.min(truncLenBits, key.length * 8);
} }
/** Retrieve the algorithm name */ /** Get the algorithm name */
public String getName() { public String getName() {
return mName; return mName;
} }
/** Retrieve the key for this algorithm */ /** Get the key for this algorithm */
public byte[] getKey() { public byte[] getKey() {
return mKey.clone(); return mKey.clone();
} }
/** /** Get the truncation length of this algorithm, in bits */
* Retrieve the truncation length, in bits, for the key in this algo. By default this will be
* the length in bits of the key.
*/
public int getTruncationLengthBits() { public int getTruncationLengthBits() {
return mTruncLenBits; return mTruncLenBits;
} }

View File

@@ -20,7 +20,12 @@ import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
/** @hide */ /**
* This class encapsulates all the configuration parameters needed to create IPsec transforms and
* policies.
*
* @hide
*/
public final class IpSecConfig implements Parcelable { public final class IpSecConfig implements Parcelable {
private static final String TAG = "IpSecConfig"; private static final String TAG = "IpSecConfig";
@@ -38,6 +43,9 @@ public final class IpSecConfig implements Parcelable {
// for outbound packets. It may also be used to select packets. // for outbound packets. It may also be used to select packets.
private Network mNetwork; private Network mNetwork;
/**
* This class captures the parameters that specifically apply to inbound or outbound traffic.
*/
public static class Flow { public static class Flow {
// Minimum requirements for identifying a transform // Minimum requirements for identifying a transform
// SPI identifying the IPsec flow in packet processing // SPI identifying the IPsec flow in packet processing

View File

@@ -19,6 +19,7 @@ import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.SystemService; import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.Context; import android.content.Context;
import android.os.Binder; import android.os.Binder;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
@@ -37,22 +38,28 @@ import java.net.InetAddress;
import java.net.Socket; import java.net.Socket;
/** /**
* This class contains methods for managing IPsec sessions, which will perform kernel-space * This class contains methods for managing IPsec sessions. Once configured, the kernel will apply
* encryption and decryption of socket or Network traffic. * confidentiality (encryption) and integrity (authentication) to IP traffic.
* *
* <p>An IpSecManager may be obtained by calling {@link * <p>Note that not all aspects of IPsec are permitted by this API. Applications may create
* android.content.Context#getSystemService(String) Context#getSystemService(String)} with {@link * transport mode security associations and apply them to individual sockets. Applications looking
* android.content.Context#IPSEC_SERVICE Context#IPSEC_SERVICE} * to create a VPN should use {@link VpnService}.
*
* @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
* Internet Protocol</a>
*/ */
@SystemService(Context.IPSEC_SERVICE) @SystemService(Context.IPSEC_SERVICE)
public final class IpSecManager { public final class IpSecManager {
private static final String TAG = "IpSecManager"; private static final String TAG = "IpSecManager";
/** /**
* The Security Parameter Index, SPI, 0 indicates an unknown or invalid index. * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index.
* *
* <p>No IPsec packet may contain an SPI of 0. * <p>No IPsec packet may contain an SPI of 0.
*
* @hide
*/ */
@TestApi
public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; public static final int INVALID_SECURITY_PARAMETER_INDEX = 0;
/** @hide */ /** @hide */
@@ -66,10 +73,12 @@ public final class IpSecManager {
public static final int INVALID_RESOURCE_ID = 0; public static final int INVALID_RESOURCE_ID = 0;
/** /**
* Indicates that the combination of remote InetAddress and SPI was non-unique for a given * Thrown to indicate that a requested SPI is in use.
* request. If encountered, selection of a new SPI is required before a transform may be *
* created. Note, this should happen very rarely if the SPI is chosen to be sufficiently random * <p>The combination of remote {@code InetAddress} and SPI must be unique across all apps on
* or reserved using reserveSecurityParameterIndex. * one device. If this error is encountered, a new SPI is required before a transform may be
* created. This error can be avoided by calling {@link
* IpSecManager#reserveSecurityParameterIndex}.
*/ */
public static final class SpiUnavailableException extends AndroidException { public static final class SpiUnavailableException extends AndroidException {
private final int mSpi; private final int mSpi;
@@ -78,24 +87,26 @@ public final class IpSecManager {
* Construct an exception indicating that a transform with the given SPI is already in use * Construct an exception indicating that a transform with the given SPI is already in use
* or otherwise unavailable. * or otherwise unavailable.
* *
* @param msg Description indicating the colliding SPI * @param msg description indicating the colliding SPI
* @param spi the SPI that could not be used due to a collision * @param spi the SPI that could not be used due to a collision
*/ */
SpiUnavailableException(String msg, int spi) { SpiUnavailableException(String msg, int spi) {
super(msg + "(spi: " + spi + ")"); super(msg + " (spi: " + spi + ")");
mSpi = spi; mSpi = spi;
} }
/** Retrieve the SPI that caused a collision */ /** Get the SPI that caused a collision. */
public int getSpi() { public int getSpi() {
return mSpi; return mSpi;
} }
} }
/** /**
* Indicates that the requested system resource for IPsec, such as a socket or other system * Thrown to indicate that an IPsec resource is unavailable.
* resource is unavailable. If this exception is thrown, try releasing allocated objects of the *
* type requested. * <p>This could apply to resources such as sockets, {@link SecurityParameterIndex}, {@link
* IpSecTransform}, or other system resources. If this exception is thrown, users should release
* allocated objects of the type requested.
*/ */
public static final class ResourceUnavailableException extends AndroidException { public static final class ResourceUnavailableException extends AndroidException {
@@ -106,6 +117,13 @@ public final class IpSecManager {
private final IIpSecService mService; private final IIpSecService mService;
/**
* This class represents a reserved SPI.
*
* <p>Objects of this type are used to track reserved security parameter indices. They can be
* obtained by calling {@link IpSecManager#reserveSecurityParameterIndex} and must be released
* by calling {@link #close()} when they are no longer needed.
*/
public static final class SecurityParameterIndex implements AutoCloseable { public static final class SecurityParameterIndex implements AutoCloseable {
private final IIpSecService mService; private final IIpSecService mService;
private final InetAddress mRemoteAddress; private final InetAddress mRemoteAddress;
@@ -113,7 +131,7 @@ public final class IpSecManager {
private int mSpi = INVALID_SECURITY_PARAMETER_INDEX; private int mSpi = INVALID_SECURITY_PARAMETER_INDEX;
private int mResourceId; private int mResourceId;
/** Return the underlying SPI held by this object */ /** Get the underlying SPI held by this object. */
public int getSpi() { public int getSpi() {
return mSpi; return mSpi;
} }
@@ -135,6 +153,7 @@ public final class IpSecManager {
mCloseGuard.close(); mCloseGuard.close();
} }
/** Check that the SPI was closed properly. */
@Override @Override
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
if (mCloseGuard != null) { if (mCloseGuard != null) {
@@ -197,13 +216,13 @@ public final class IpSecManager {
} }
/** /**
* Reserve an SPI for traffic bound towards the specified remote address. * Reserve a random SPI for traffic bound to or from the specified remote address.
* *
* <p>If successful, this SPI is guaranteed available until released by a call to {@link * <p>If successful, this SPI is guaranteed available until released by a call to {@link
* SecurityParameterIndex#close()}. * SecurityParameterIndex#close()}.
* *
* @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT} * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT}
* @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress. * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress
* @return the reserved SecurityParameterIndex * @return the reserved SecurityParameterIndex
* @throws ResourceUnavailableException indicating that too many SPIs are currently allocated * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated
* for this user * for this user
@@ -223,17 +242,18 @@ public final class IpSecManager {
} }
/** /**
* Reserve an SPI for traffic bound towards the specified remote address. * Reserve the requested SPI for traffic bound to or from the specified remote address.
* *
* <p>If successful, this SPI is guaranteed available until released by a call to {@link * <p>If successful, this SPI is guaranteed available until released by a call to {@link
* SecurityParameterIndex#close()}. * SecurityParameterIndex#close()}.
* *
* @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT} * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT}
* @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress. * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress
* @param requestedSpi the requested SPI, or '0' to allocate a random SPI. * @param requestedSpi the requested SPI, or '0' to allocate a random SPI
* @return the reserved SecurityParameterIndex * @return the reserved SecurityParameterIndex
* @throws ResourceUnavailableException indicating that too many SPIs are currently allocated * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated
* for this user * for this user
* @throws SpiUnavailableException indicating that the requested SPI could not be reserved
*/ */
public SecurityParameterIndex reserveSecurityParameterIndex( public SecurityParameterIndex reserveSecurityParameterIndex(
int direction, InetAddress remoteAddress, int requestedSpi) int direction, InetAddress remoteAddress, int requestedSpi)
@@ -245,16 +265,28 @@ public final class IpSecManager {
} }
/** /**
* Apply an active Transport Mode IPsec Transform to a stream socket to perform IPsec * Apply an IPsec transform to a stream socket.
* encapsulation of the traffic flowing between the socket and the remote InetAddress of that *
* transform. For security reasons, attempts to send traffic to any IP address other than the * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
* address associated with that transform will throw an IOException. In addition, if the * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
* IpSecTransform is later deactivated, the socket will throw an IOException on any calls to * the transform is removed from the socket by calling {@link #removeTransportModeTransform},
* send() or receive() until the transform is removed from the socket by calling {@link * unprotected traffic can resume on that socket.
* #removeTransportModeTransform(Socket, IpSecTransform)}; *
* <p>For security reasons, the destination address of any traffic on the socket must match the
* remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
* other IP address will result in an IOException. In addition, reads and writes on the socket
* will throw IOException if the user deactivates the transform (by calling {@link
* IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}.
*
* <h4>Rekey Procedure</h4> <p>When applying a new tranform to a socket, the previous transform
* will be removed. However, inbound traffic on the old transform will continue to be decrypted
* until that transform is deallocated by calling {@link IpSecTransform#close()}. This overlap
* allows rekey procedures where both transforms are valid until both endpoints are using the
* new transform and all in-flight packets have been received.
* *
* @param socket a stream socket * @param socket a stream socket
* @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform. * @param transform a transport mode {@code IpSecTransform}
* @throws IOException indicating that the transform could not be applied
* @hide * @hide
*/ */
public void applyTransportModeTransform(Socket socket, IpSecTransform transform) public void applyTransportModeTransform(Socket socket, IpSecTransform transform)
@@ -265,16 +297,28 @@ public final class IpSecManager {
} }
/** /**
* Apply an active Transport Mode IPsec Transform to a datagram socket to perform IPsec * Apply an IPsec transform to a datagram socket.
* encapsulation of the traffic flowing between the socket and the remote InetAddress of that *
* transform. For security reasons, attempts to send traffic to any IP address other than the * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
* address associated with that transform will throw an IOException. In addition, if the * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
* IpSecTransform is later deactivated, the socket will throw an IOException on any calls to * the transform is removed from the socket by calling {@link #removeTransportModeTransform},
* send() or receive() until the transform is removed from the socket by calling {@link * unprotected traffic can resume on that socket.
* #removeTransportModeTransform(DatagramSocket, IpSecTransform)}; *
* <p>For security reasons, the destination address of any traffic on the socket must match the
* remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
* other IP address will result in an IOException. In addition, reads and writes on the socket
* will throw IOException if the user deactivates the transform (by calling {@link
* IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}.
*
* <h4>Rekey Procedure</h4> <p>When applying a new tranform to a socket, the previous transform
* will be removed. However, inbound traffic on the old transform will continue to be decrypted
* until that transform is deallocated by calling {@link IpSecTransform#close()}. This overlap
* allows rekey procedures where both transforms are valid until both endpoints are using the
* new transform and all in-flight packets have been received.
* *
* @param socket a datagram socket * @param socket a datagram socket
* @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform. * @param transform a transport mode {@code IpSecTransform}
* @throws IOException indicating that the transform could not be applied
* @hide * @hide
*/ */
public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform) public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
@@ -285,16 +329,28 @@ public final class IpSecManager {
} }
/** /**
* Apply an active Transport Mode IPsec Transform to a stream socket to perform IPsec * Apply an IPsec transform to a socket.
* encapsulation of the traffic flowing between the socket and the remote InetAddress of that *
* transform. For security reasons, attempts to send traffic to any IP address other than the * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
* address associated with that transform will throw an IOException. In addition, if the * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
* IpSecTransform is later deactivated, the socket will throw an IOException on any calls to * the transform is removed from the socket by calling {@link #removeTransportModeTransform},
* send() or receive() until the transform is removed from the socket by calling {@link * unprotected traffic can resume on that socket.
* #removeTransportModeTransform(FileDescriptor, IpSecTransform)}; *
* <p>For security reasons, the destination address of any traffic on the socket must match the
* remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
* other IP address will result in an IOException. In addition, reads and writes on the socket
* will throw IOException if the user deactivates the transform (by calling {@link
* IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}.
*
* <h4>Rekey Procedure</h4> <p>When applying a new tranform to a socket, the previous transform
* will be removed. However, inbound traffic on the old transform will continue to be decrypted
* until that transform is deallocated by calling {@link IpSecTransform#close()}. This overlap
* allows rekey procedures where both transforms are valid until both endpoints are using the
* new transform and all in-flight packets have been received.
* *
* @param socket a socket file descriptor * @param socket a socket file descriptor
* @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform. * @param transform a transport mode {@code IpSecTransform}
* @throws IOException indicating that the transform could not be applied
*/ */
public void applyTransportModeTransform(FileDescriptor socket, IpSecTransform transform) public void applyTransportModeTransform(FileDescriptor socket, IpSecTransform transform)
throws IOException { throws IOException {
@@ -323,6 +379,7 @@ public final class IpSecManager {
* Applications should probably not use this API directly. Instead, they should use {@link * Applications should probably not use this API directly. Instead, they should use {@link
* VpnService} to provide VPN capability in a more generic fashion. * VpnService} to provide VPN capability in a more generic fashion.
* *
* TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked.
* @param net a {@link Network} that will be tunneled via IP Sec. * @param net a {@link Network} that will be tunneled via IP Sec.
* @param transform an {@link IpSecTransform}, which must be an active Tunnel Mode transform. * @param transform an {@link IpSecTransform}, which must be an active Tunnel Mode transform.
* @hide * @hide
@@ -330,14 +387,19 @@ public final class IpSecManager {
public void applyTunnelModeTransform(Network net, IpSecTransform transform) {} public void applyTunnelModeTransform(Network net, IpSecTransform transform) {}
/** /**
* Remove a transform from a given stream socket. Once removed, traffic on the socket will not * Remove an IPsec transform from a stream socket.
* be encypted. This allows sockets that have been used for IPsec to be reclaimed for
* communication in the clear in the event socket reuse is desired. This operation will succeed
* regardless of the underlying state of a transform. If a transform is removed, communication
* on all sockets to which that transform was applied will fail until this method is called.
* *
* @param socket a socket that previously had a transform applied to it. * <p>Once removed, traffic on the socket will not be encrypted. This operation will succeed
* regardless of the state of the transform. Removing a transform from a socket allows the
* socket to be reused for communication in the clear.
*
* <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
* {@link IpSecTransform#close()}, then communication on the socket will fail until this method
* is called.
*
* @param socket a socket that previously had a transform applied to it
* @param transform the IPsec Transform that was previously applied to the given socket * @param transform the IPsec Transform that was previously applied to the given socket
* @throws IOException indicating that the transform could not be removed from the socket
* @hide * @hide
*/ */
public void removeTransportModeTransform(Socket socket, IpSecTransform transform) public void removeTransportModeTransform(Socket socket, IpSecTransform transform)
@@ -348,14 +410,19 @@ public final class IpSecManager {
} }
/** /**
* Remove a transform from a given datagram socket. Once removed, traffic on the socket will not * Remove an IPsec transform from a datagram socket.
* be encypted. This allows sockets that have been used for IPsec to be reclaimed for
* communication in the clear in the event socket reuse is desired. This operation will succeed
* regardless of the underlying state of a transform. If a transform is removed, communication
* on all sockets to which that transform was applied will fail until this method is called.
* *
* @param socket a socket that previously had a transform applied to it. * <p>Once removed, traffic on the socket will not be encrypted. This operation will succeed
* regardless of the state of the transform. Removing a transform from a socket allows the
* socket to be reused for communication in the clear.
*
* <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
* {@link IpSecTransform#close()}, then communication on the socket will fail until this method
* is called.
*
* @param socket a socket that previously had a transform applied to it
* @param transform the IPsec Transform that was previously applied to the given socket * @param transform the IPsec Transform that was previously applied to the given socket
* @throws IOException indicating that the transform could not be removed from the socket
* @hide * @hide
*/ */
public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform) public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
@@ -366,14 +433,19 @@ public final class IpSecManager {
} }
/** /**
* Remove a transform from a given stream socket. Once removed, traffic on the socket will not * Remove an IPsec transform from a socket.
* be encypted. This allows sockets that have been used for IPsec to be reclaimed for
* communication in the clear in the event socket reuse is desired. This operation will succeed
* regardless of the underlying state of a transform. If a transform is removed, communication
* on all sockets to which that transform was applied will fail until this method is called.
* *
* @param socket a socket file descriptor that previously had a transform applied to it. * <p>Once removed, traffic on the socket will not be encrypted. This operation will succeed
* regardless of the state of the transform. Removing a transform from a socket allows the
* socket to be reused for communication in the clear.
*
* <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
* {@link IpSecTransform#close()}, then communication on the socket will fail until this method
* is called.
*
* @param socket a socket that previously had a transform applied to it
* @param transform the IPsec Transform that was previously applied to the given socket * @param transform the IPsec Transform that was previously applied to the given socket
* @throws IOException indicating that the transform could not be removed from the socket
*/ */
public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform) public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform)
throws IOException { throws IOException {
@@ -382,7 +454,7 @@ public final class IpSecManager {
} }
} }
/* Call down to activate a transform */ /* Call down to remove a transform */
private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {
try { try {
mService.removeTransportModeTransform(pfd, transform.getResourceId()); mService.removeTransportModeTransform(pfd, transform.getResourceId());
@@ -397,6 +469,7 @@ public final class IpSecManager {
* all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is * all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is
* lost, all traffic will drop. * lost, all traffic will drop.
* *
* TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked.
* @param net a network that currently has transform applied to it. * @param net a network that currently has transform applied to it.
* @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given * @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given
* network * network
@@ -405,11 +478,18 @@ public final class IpSecManager {
public void removeTunnelModeTransform(Network net, IpSecTransform transform) {} public void removeTunnelModeTransform(Network net, IpSecTransform transform) {}
/** /**
* Class providing access to a system-provided UDP Encapsulation Socket, which may be used for * This class provides access to a UDP encapsulation Socket.
* IKE signalling as well as for inbound and outbound UDP encapsulated IPsec traffic.
* *
* <p>The socket provided by this class cannot be re-bound or closed via the inner * <p>{@code UdpEncapsulationSocket} wraps a system-provided datagram socket intended for IKEv2
* FileDescriptor. Instead, disposing of this socket requires a call to close(). * signalling and UDP encapsulated IPsec traffic. Instances can be obtained by calling {@link
* IpSecManager#openUdpEncapsulationSocket}. The provided socket cannot be re-bound by the
* caller. The caller should not close the {@code FileDescriptor} returned by {@link
* #getSocket}, but should use {@link #close} instead.
*
* <p>Allowing the user to close or unbind a UDP encapsulation socket could impact the traffic
* of the next user who binds to that port. To prevent this scenario, these sockets are held
* open by the system so that they may only be closed by calling {@link #close} or when the user
* process exits.
*/ */
public static final class UdpEncapsulationSocket implements AutoCloseable { public static final class UdpEncapsulationSocket implements AutoCloseable {
private final ParcelFileDescriptor mPfd; private final ParcelFileDescriptor mPfd;
@@ -443,7 +523,7 @@ public final class IpSecManager {
mCloseGuard.open("constructor"); mCloseGuard.open("constructor");
} }
/** Access the inner UDP Encapsulation Socket */ /** Get the wrapped socket. */
public FileDescriptor getSocket() { public FileDescriptor getSocket() {
if (mPfd == null) { if (mPfd == null) {
return null; return null;
@@ -451,22 +531,19 @@ public final class IpSecManager {
return mPfd.getFileDescriptor(); return mPfd.getFileDescriptor();
} }
/** Retrieve the port number of the inner encapsulation socket */ /** Get the bound port of the wrapped socket. */
public int getPort() { public int getPort() {
return mPort; return mPort;
} }
@Override
/** /**
* Release the resources that have been reserved for this Socket. * Close this socket.
* *
* <p>This method closes the underlying socket, reducing a user's allocated sockets in the * <p>This closes the wrapped socket. Open encapsulation sockets count against a user's
* system. This must be done as part of cleanup following use of a socket. Failure to do so * resource limits, and forgetting to close them eventually will result in {@link
* will cause the socket to count against a total allocation limit for IpSec and eventually * ResourceUnavailableException} being thrown.
* fail due to resource limits.
*
* @param fd a file descriptor previously returned as a UDP Encapsulation socket.
*/ */
@Override
public void close() throws IOException { public void close() throws IOException {
try { try {
mService.closeUdpEncapsulationSocket(mResourceId); mService.closeUdpEncapsulationSocket(mResourceId);
@@ -483,6 +560,7 @@ public final class IpSecManager {
mCloseGuard.close(); mCloseGuard.close();
} }
/** Check that the socket was closed properly. */
@Override @Override
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
if (mCloseGuard != null) { if (mCloseGuard != null) {
@@ -499,21 +577,14 @@ public final class IpSecManager {
}; };
/** /**
* Open a socket that is bound to a free UDP port on the system. * Open a socket for UDP encapsulation and bind to the given port.
* *
* <p>By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket.
* the caller. This provides safe access to a socket on a port that can later be used as a UDP
* Encapsulation port.
* *
* <p>This socket reservation works in conjunction with IpSecTransforms, which may re-use the * @param port a local UDP port
* socket port. Explicitly opening this port is only necessary if communication is desired on * @return a socket that is bound to the given port
* that port. * @throws IOException indicating that the socket could not be opened or bound
* * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
* @param port a local UDP port to be reserved for UDP Encapsulation. is provided, then this
* method will bind to the specified port or fail. To retrieve the port number, call {@link
* android.system.Os#getsockname(FileDescriptor)}.
* @return a {@link UdpEncapsulationSocket} that is bound to the requested port for the lifetime
* of the object.
*/ */
// Returning a socket in this fashion that has been created and bound by the system // Returning a socket in this fashion that has been created and bound by the system
// is the only safe way to ensure that a socket is both accessible to the user and // is the only safe way to ensure that a socket is both accessible to the user and
@@ -533,17 +604,16 @@ public final class IpSecManager {
} }
/** /**
* Open a socket that is bound to a port selected by the system. * Open a socket for UDP encapsulation.
* *
* <p>By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket.
* the caller. This provides safe access to a socket on a port that can later be used as a UDP
* Encapsulation port.
* *
* <p>This socket reservation works in conjunction with IpSecTransforms, which may re-use the * <p>The local port of the returned socket can be obtained by calling {@link
* socket port. Explicitly opening this port is only necessary if communication is desired on * UdpEncapsulationSocket#getPort()}.
* that port.
* *
* @return a {@link UdpEncapsulationSocket} that is bound to an arbitrarily selected port * @return a socket that is bound to a local port
* @throws IOException indicating that the socket could not be opened or bound
* @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
*/ */
// Returning a socket in this fashion that has been created and bound by the system // Returning a socket in this fashion that has been created and bound by the system
// is the only safe way to ensure that a socket is both accessible to the user and // is the only safe way to ensure that a socket is both accessible to the user and
@@ -556,7 +626,7 @@ public final class IpSecManager {
} }
/** /**
* Retrieve an instance of an IpSecManager within you application context * Construct an instance of IpSecManager within an application context.
* *
* @param context the application context for this manager * @param context the application context for this manager
* @hide * @hide

View File

@@ -38,27 +38,29 @@ import java.lang.annotation.RetentionPolicy;
import java.net.InetAddress; import java.net.InetAddress;
/** /**
* This class represents an IpSecTransform, which encapsulates both properties and state of IPsec. * This class represents an IPsec transform, which comprises security associations in one or both
* directions.
* *
* <p>IpSecTransforms must be built from an IpSecTransform.Builder, and they must persist throughout * <p>Transforms are created using {@link IpSecTransform.Builder}. Each {@code IpSecTransform}
* the lifetime of the underlying transform. If a transform object leaves scope, the underlying * object encapsulates the properties and state of an inbound and outbound IPsec security
* transform may be disabled automatically, with likely undesirable results. * association. That includes, but is not limited to, algorithm choice, key material, and allocated
* system resources.
* *
* <p>An IpSecTransform may either represent a tunnel mode transform that operates on a wide array * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
* of traffic or may represent a transport mode transform operating on a Socket or Sockets. * Internet Protocol</a>
*/ */
public final class IpSecTransform implements AutoCloseable { public final class IpSecTransform implements AutoCloseable {
private static final String TAG = "IpSecTransform"; private static final String TAG = "IpSecTransform";
/** /**
* For direction-specific attributes of an IpSecTransform, indicates that an attribute applies * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute
* to traffic towards the host. * applies to traffic towards the host.
*/ */
public static final int DIRECTION_IN = 0; public static final int DIRECTION_IN = 0;
/** /**
* For direction-specific attributes of an IpSecTransform, indicates that an attribute applies * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute
* to traffic from the host. * applies to traffic from the host.
*/ */
public static final int DIRECTION_OUT = 1; public static final int DIRECTION_OUT = 1;
@@ -77,16 +79,16 @@ public final class IpSecTransform implements AutoCloseable {
public static final int ENCAP_NONE = 0; public static final int ENCAP_NONE = 0;
/** /**
* IpSec traffic will be encapsulated within a UDP header with an additional 8-byte header pad * IPsec traffic will be encapsulated within UDP, but with 8 zero-value bytes between the UDP
* (of '0'-value bytes) that prevents traffic from being interpreted as IKE or as ESP over UDP. * header and payload. This prevents traffic from being interpreted as ESP or IKEv2.
* *
* @hide * @hide
*/ */
public static final int ENCAP_ESPINUDP_NON_IKE = 1; public static final int ENCAP_ESPINUDP_NON_IKE = 1;
/** /**
* IpSec traffic will be encapsulated within UDP as per <a * IPsec traffic will be encapsulated within UDP as per
* href="https://tools.ietf.org/html/rfc3948">RFC3498</a>. * <a href="https://tools.ietf.org/html/rfc3948">RFC 3498</a>.
* *
* @hide * @hide
*/ */
@@ -165,13 +167,14 @@ public final class IpSecTransform implements AutoCloseable {
} }
/** /**
* Deactivate an IpSecTransform and free all resources for that transform that are managed by * Deactivate this {@code IpSecTransform} and free allocated resources.
* the system for this Transform.
* *
* <p>Deactivating a transform while it is still applied to any Socket will result in sockets * <p>Deactivating a transform while it is still applied to a socket will result in errors on
* refusing to send or receive data. This method will silently succeed if the specified * that socket. Make sure to remove transforms by calling {@link
* transform has already been removed; thus, it is always safe to attempt cleanup when a * IpSecManager#removeTransportModeTransform}. Note, removing an {@code IpSecTransform} from a
* transform is no longer needed. * socket will not deactivate it (because one transform may be applied to multiple sockets).
*
* <p>It is safe to call this method on a transform that has already been deactivated.
*/ */
public void close() { public void close() {
Log.d(TAG, "Removing Transform with Id " + mResourceId); Log.d(TAG, "Removing Transform with Id " + mResourceId);
@@ -197,6 +200,7 @@ public final class IpSecTransform implements AutoCloseable {
} }
} }
/** Check that the transform was closed properly. */
@Override @Override
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
if (mCloseGuard != null) { if (mCloseGuard != null) {
@@ -264,65 +268,63 @@ public final class IpSecTransform implements AutoCloseable {
} }
/** /**
* Builder object to facilitate the creation of IpSecTransform objects. * This class is used to build {@link IpSecTransform} objects.
*
* <p>Apply additional properties to the transform and then call a build() method to return an
* IpSecTransform object.
*
* @see Builder#buildTransportModeTransform(InetAddress)
*/ */
public static class Builder { public static class Builder {
private Context mContext; private Context mContext;
private IpSecConfig mConfig; private IpSecConfig mConfig;
/** /**
* Add an encryption algorithm to the transform for the given direction. * Set the encryption algorithm for the given direction.
* *
* <p>If encryption is set for a given direction without also providing an SPI for that * <p>If encryption is set for a direction without also providing an SPI for that direction,
* direction, creation of an IpSecTransform will fail upon calling a build() method. * creation of an {@code IpSecTransform} will fail when attempting to build the transform.
* *
* <p>Authenticated encryption is mutually exclusive with encryption and authentication. * <p>Encryption is mutually exclusive with authenticated encryption.
* *
* @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT} * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT}
* @param algo {@link IpSecAlgorithm} specifying the encryption to be applied. * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied.
*/ */
public IpSecTransform.Builder setEncryption( public IpSecTransform.Builder setEncryption(
@TransformDirection int direction, IpSecAlgorithm algo) { @TransformDirection int direction, IpSecAlgorithm algo) {
// TODO: throw IllegalArgumentException if algo is not an encryption algorithm.
mConfig.setEncryption(direction, algo); mConfig.setEncryption(direction, algo);
return this; return this;
} }
/** /**
* Add an authentication/integrity algorithm to the transform. * Set the authentication (integrity) algorithm for the given direction.
* *
* <p>If authentication is set for a given direction without also providing an SPI for that * <p>If authentication is set for a direction without also providing an SPI for that
* direction, creation of an IpSecTransform will fail upon calling a build() method. * direction, creation of an {@code IpSecTransform} will fail when attempting to build the
* transform.
* *
* <p>Authenticated encryption is mutually exclusive with encryption and authentication. * <p>Authentication is mutually exclusive with authenticated encryption.
* *
* @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT} * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT}
* @param algo {@link IpSecAlgorithm} specifying the authentication to be applied. * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied.
*/ */
public IpSecTransform.Builder setAuthentication( public IpSecTransform.Builder setAuthentication(
@TransformDirection int direction, IpSecAlgorithm algo) { @TransformDirection int direction, IpSecAlgorithm algo) {
// TODO: throw IllegalArgumentException if algo is not an authentication algorithm.
mConfig.setAuthentication(direction, algo); mConfig.setAuthentication(direction, algo);
return this; return this;
} }
/** /**
* Add an authenticated encryption algorithm to the transform for the given direction. * Set the authenticated encryption algorithm for the given direction.
* *
* <p>If an authenticated encryption algorithm is set for a given direction without also * <p>If an authenticated encryption algorithm is set for a given direction without also
* providing an SPI for that direction, creation of an IpSecTransform will fail upon calling * providing an SPI for that direction, creation of an {@code IpSecTransform} will fail when
* a build() method. * attempting to build the transform.
* *
* <p>The Authenticated Encryption (AE) class of algorithms are also known as Authenticated * <p>The Authenticated Encryption (AE) class of algorithms are also known as Authenticated
* Encryption with Associated Data (AEAD) algorithms, or Combined mode algorithms (as * Encryption with Associated Data (AEAD) algorithms, or Combined mode algorithms (as
* referred to in RFC 4301) * referred to in <a href="https://tools.ietf.org/html/rfc4301">RFC 4301</a>).
* *
* <p>Authenticated encryption is mutually exclusive with encryption and authentication. * <p>Authenticated encryption is mutually exclusive with encryption and authentication.
* *
* @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT} * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT}
* @param algo {@link IpSecAlgorithm} specifying the authenticated encryption algorithm to * @param algo {@link IpSecAlgorithm} specifying the authenticated encryption algorithm to
* be applied. * be applied.
*/ */
@@ -333,19 +335,16 @@ public final class IpSecTransform implements AutoCloseable {
} }
/** /**
* Set the SPI, which uniquely identifies a particular IPsec session from others. Because * Set the SPI for the given direction.
* IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a
* given destination address.
* *
* <p>Care should be chosen when selecting an SPI to ensure that is is as unique as * <p>Because IPsec operates at the IP layer, this 32-bit identifier uniquely identifies
* possible. To reserve a value call {@link IpSecManager#reserveSecurityParameterIndex(int, * packets to a given destination address. To prevent SPI collisions, values should be
* InetAddress, int)}. Otherwise, SPI collisions would prevent a transform from being * reserved by calling {@link IpSecManager#reserveSecurityParameterIndex}.
* activated. IpSecManager#reserveSecurityParameterIndex(int, InetAddres$s, int)}.
* *
* <p>Unless an SPI is set for a given direction, traffic in that direction will be * <p>If the SPI and algorithms are omitted for one direction, traffic in that direction
* sent/received without any IPsec applied. * will not be encrypted or authenticated.
* *
* @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT} * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT}
* @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed
* traffic * traffic
*/ */
@@ -356,11 +355,10 @@ public final class IpSecTransform implements AutoCloseable {
} }
/** /**
* Specify the network on which this transform will emit its traffic; (otherwise it will * Set the {@link Network} which will carry tunneled traffic.
* emit on the default network).
* *
* <p>Restricts the transformed traffic to a particular {@link Network}. This is required in * <p>Restricts the transformed traffic to a particular {@link Network}. This is required
* tunnel mode. * for tunnel mode, otherwise tunneled traffic would be sent on the default network.
* *
* @hide * @hide
*/ */
@@ -371,15 +369,18 @@ public final class IpSecTransform implements AutoCloseable {
} }
/** /**
* Add UDP encapsulation to an IPv4 transform * Add UDP encapsulation to an IPv4 transform.
* *
* <p>This option allows IPsec traffic to pass through NAT. Refer to RFC 3947 and 3948 for * <p>This allows IPsec traffic to pass through a NAT.
* details on how UDP should be applied to IPsec.
* *
* @param localSocket a {@link IpSecManager.UdpEncapsulationSocket} for sending and * @see <a href="https://tools.ietf.org/html/rfc3948">RFC 3948, UDP Encapsulation of IPsec
* receiving encapsulating traffic. * ESP Packets</a>
* @param remotePort the UDP port number of the remote that will send and receive * @see <a href="https://tools.ietf.org/html/rfc7296#section-2.23">RFC 7296 section 2.23,
* encapsulated traffic. In the case of IKE, this is likely port 4500. * NAT Traversal of IKEv2</a>
*
* @param localSocket a socket for sending and receiving encapsulated traffic
* @param remotePort the UDP port number of the remote host that will send and receive
* encapsulated traffic. In the case of IKEv2, this should be port 4500.
*/ */
public IpSecTransform.Builder setIpv4Encapsulation( public IpSecTransform.Builder setIpv4Encapsulation(
IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) { IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) {
@@ -393,12 +394,15 @@ public final class IpSecTransform implements AutoCloseable {
// TODO: Probably a better exception to throw for NATTKeepalive failure // TODO: Probably a better exception to throw for NATTKeepalive failure
// TODO: Specify the needed NATT keepalive permission. // TODO: Specify the needed NATT keepalive permission.
/** /**
* Send a NATT Keepalive packet with a given maximum interval. This will create an offloaded * Set NAT-T keepalives to be sent with a given interval.
* request to do power-efficient NATT Keepalive. If NATT keepalive is requested but cannot *
* be activated, then the transform will fail to activate and throw an IOException. * <p>This will set power-efficient keepalive packets to be sent by the system. If NAT-T
* keepalive is requested but cannot be activated, then creation of an {@link
* IpSecTransform} will fail when calling the build method.
*
* @param intervalSeconds the maximum number of seconds between keepalive packets. Must be
* between 20s and 3600s.
* *
* @param intervalSeconds the maximum number of seconds between keepalive packets, no less
* than 20s and no more than 3600s.
* @hide * @hide
*/ */
@SystemApi @SystemApi
@@ -408,36 +412,29 @@ public final class IpSecTransform implements AutoCloseable {
} }
/** /**
* Build and return an active {@link IpSecTransform} object as a Transport Mode Transform. * Build a transport mode {@link IpSecTransform}.
* Some parameters have interdependencies that are checked at build time. If a well-formed
* transform cannot be created from the supplied parameters, this method will throw an
* Exception.
* *
* <p>Upon a successful return from this call, the provided IpSecTransform will be active * <p>This builds and activates a transport mode transform. Note that an active transform
* and may be applied to sockets. If too many IpSecTransform objects are active for a given * will not affect any network traffic until it has been applied to one or more sockets.
* user this operation will fail and throw ResourceUnavailableException. To avoid these
* exceptions, unused Transform objects must be cleaned up by calling {@link
* IpSecTransform#close()} when they are no longer needed.
* *
* @param remoteAddress the {@link InetAddress} that, when matched on traffic to/from this * @see IpSecManager#applyTransportModeTransform
* socket will cause the transform to be applied. *
* <p>Note that an active transform will not impact any network traffic until it has * @param remoteAddress the remote {@code InetAddress} of traffic on sockets that will use
* been applied to one or more Sockets. Calling this method is a necessary precondition * this transform
* for applying it to a socket, but is not sufficient to actually apply IPsec.
* @throws IllegalArgumentException indicating that a particular combination of transform * @throws IllegalArgumentException indicating that a particular combination of transform
* properties is invalid. * properties is invalid
* @throws IpSecManager.ResourceUnavailableException in the event that no more Transforms * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms are
* may be allocated * active
* @throws SpiUnavailableException if the SPI collides with an existing transform * @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI
* (unlikely). * collides with an existing transform
* @throws ResourceUnavailableException if the current user currently has exceeded the * @throws IOException indicating other errors
* number of allowed active transforms.
*/ */
public IpSecTransform buildTransportModeTransform(InetAddress remoteAddress) public IpSecTransform buildTransportModeTransform(InetAddress remoteAddress)
throws IpSecManager.ResourceUnavailableException, throws IpSecManager.ResourceUnavailableException,
IpSecManager.SpiUnavailableException, IOException { IpSecManager.SpiUnavailableException, IOException {
mConfig.setMode(MODE_TRANSPORT); mConfig.setMode(MODE_TRANSPORT);
mConfig.setRemoteAddress(remoteAddress.getHostAddress()); mConfig.setRemoteAddress(remoteAddress.getHostAddress());
// FIXME: modifying a builder after calling build can change the built transform.
return new IpSecTransform(mContext, mConfig).activate(); return new IpSecTransform(mContext, mConfig).activate();
} }
@@ -465,9 +462,9 @@ public final class IpSecTransform implements AutoCloseable {
} }
/** /**
* Create a new IpSecTransform.Builder to construct an IpSecTransform * Create a new IpSecTransform.Builder.
* *
* @param context current Context * @param context current context
*/ */
public Builder(@NonNull Context context) { public Builder(@NonNull Context context) {
Preconditions.checkNotNull(context); Preconditions.checkNotNull(context);