diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 64f8f39e2b..d6e62cf1f8 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -15,6 +15,7 @@ */ package android.net; +import android.annotation.NonNull; import android.annotation.StringDef; import android.os.Build; import android.os.Parcel; @@ -27,8 +28,10 @@ import java.lang.annotation.RetentionPolicy; import java.util.Arrays; /** - * IpSecAlgorithm specifies a single algorithm that can be applied to an IpSec Transform. Refer to - * RFC 4301. + * This class represents a single algorithm that can be used by an {@link IpSecTransform}. + * + * @see RFC 4301, Security Architecture for the + * Internet Protocol */ 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)"; /** - * MD5 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in new - * applications and is provided for legacy compatibility with 3gpp infrastructure. + * MD5 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in + * new applications and is provided for legacy compatibility with 3gpp infrastructure. * *
Valid truncation lengths are multiples of 8 bits from 96 to (default) 128. */ public static final String AUTH_HMAC_MD5 = "hmac(md5)"; /** - * SHA1 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in - * new applications and is provided for legacy compatibility with 3gpp infrastructure. + * SHA1 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in + * new applications and is provided for legacy compatibility with 3gpp infrastructure. * *
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)"; /** - * SHA512 HMAC Authentication/Integrity Algorithm + * SHA512 HMAC Authentication/Integrity Algorithm. * *
Valid truncation lengths are multiples of 8 bits from 256 to (default) 512. */ @@ -80,9 +83,9 @@ public final class IpSecAlgorithm implements Parcelable { * *
Valid lengths for keying material are {160, 224, 288}. * - *
As per RFC4106 (Section 8.1), keying material consists of a 128, 192, or 256 bit AES key - * followed by a 32-bit salt. RFC compliance requires that the salt must be unique per - * invocation with the same key. + *
As per RFC4106 (Section + * 8.1), keying material consists of a 128, 192, or 256 bit AES key followed by a 32-bit + * salt. RFC compliance requires that the salt must be unique per invocation with the same key. * *
Valid ICV (truncation) lengths are {64, 96, 128}. */ @@ -105,48 +108,47 @@ public final class IpSecAlgorithm implements Parcelable { private final int mTruncLenBits; /** - * Specify a IpSecAlgorithm of one of the supported types including the truncation length of the - * algorithm + * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are + * defined as constants in this class. * - * @param algorithm type for IpSec. - * @param key non-null Key padded to a multiple of 8 bits. + * @param algorithm name of the algorithm. + * @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); } /** - * Specify a IpSecAlgorithm of one of the supported types including the truncation length of the - * algorithm + * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are + * defined as constants in this class. * - * @param algoName precise name of the algorithm to be used. - * @param key non-null Key padded to a multiple of 8 bits. - * @param truncLenBits the number of bits of output hash to use; only meaningful for - * Authentication or Authenticated Encryption (equivalent to ICV length). + *
This constructor only supports algorithms that use a truncation length. i.e. + * Authentication and Authenticated Encryption algorithms. + * + * @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) { - if (!isTruncationLengthValid(algoName, truncLenBits)) { + public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) { + if (!isTruncationLengthValid(algorithm, truncLenBits)) { throw new IllegalArgumentException("Unknown algorithm or invalid length"); } - mName = algoName; + mName = algorithm; mKey = key.clone(); mTruncLenBits = Math.min(truncLenBits, key.length * 8); } - /** Retrieve the algorithm name */ + /** Get the algorithm name */ public String getName() { return mName; } - /** Retrieve the key for this algorithm */ + /** Get the key for this algorithm */ public byte[] getKey() { return mKey.clone(); } - /** - * Retrieve the truncation length, in bits, for the key in this algo. By default this will be - * the length in bits of the key. - */ + /** Get the truncation length of this algorithm, in bits */ public int getTruncationLengthBits() { return mTruncLenBits; } diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index 61b13a922d..e6cd3fc130 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -20,7 +20,12 @@ import android.os.Parcelable; 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 { 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. private Network mNetwork; + /** + * This class captures the parameters that specifically apply to inbound or outbound traffic. + */ public static class Flow { // Minimum requirements for identifying a transform // SPI identifying the IPsec flow in packet processing diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index eccd5f47f2..a9e60ec88a 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -19,6 +19,7 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; import android.annotation.SystemService; +import android.annotation.TestApi; import android.content.Context; import android.os.Binder; import android.os.ParcelFileDescriptor; @@ -37,22 +38,28 @@ import java.net.InetAddress; import java.net.Socket; /** - * This class contains methods for managing IPsec sessions, which will perform kernel-space - * encryption and decryption of socket or Network traffic. + * This class contains methods for managing IPsec sessions. Once configured, the kernel will apply + * confidentiality (encryption) and integrity (authentication) to IP traffic. * - *
An IpSecManager may be obtained by calling {@link - * android.content.Context#getSystemService(String) Context#getSystemService(String)} with {@link - * android.content.Context#IPSEC_SERVICE Context#IPSEC_SERVICE} + *
Note that not all aspects of IPsec are permitted by this API. Applications may create + * transport mode security associations and apply them to individual sockets. Applications looking + * to create a VPN should use {@link VpnService}. + * + * @see RFC 4301, Security Architecture for the + * Internet Protocol */ @SystemService(Context.IPSEC_SERVICE) public final class 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. * *
No IPsec packet may contain an SPI of 0. + * + * @hide */ + @TestApi public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; /** @hide */ @@ -66,10 +73,12 @@ public final class IpSecManager { public static final int INVALID_RESOURCE_ID = 0; /** - * Indicates that the combination of remote InetAddress and SPI was non-unique for a given - * 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 - * or reserved using reserveSecurityParameterIndex. + * Thrown to indicate that a requested SPI is in use. + * + *
The combination of remote {@code InetAddress} and SPI must be unique across all apps on + * 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 { 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 * 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 */ SpiUnavailableException(String msg, int spi) { - super(msg + "(spi: " + spi + ")"); + super(msg + " (spi: " + spi + ")"); mSpi = spi; } - /** Retrieve the SPI that caused a collision */ + /** Get the SPI that caused a collision. */ public int getSpi() { return mSpi; } } /** - * Indicates that the requested system resource for IPsec, such as a socket or other system - * resource is unavailable. If this exception is thrown, try releasing allocated objects of the - * type requested. + * Thrown to indicate that an IPsec resource is unavailable. + * + *
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 { @@ -106,6 +117,13 @@ public final class IpSecManager { private final IIpSecService mService; + /** + * This class represents a reserved SPI. + * + *
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 { private final IIpSecService mService; private final InetAddress mRemoteAddress; @@ -113,7 +131,7 @@ public final class IpSecManager { private int mSpi = INVALID_SECURITY_PARAMETER_INDEX; private int mResourceId; - /** Return the underlying SPI held by this object */ + /** Get the underlying SPI held by this object. */ public int getSpi() { return mSpi; } @@ -135,6 +153,7 @@ public final class IpSecManager { mCloseGuard.close(); } + /** Check that the SPI was closed properly. */ @Override protected void finalize() throws Throwable { 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. * *
If successful, this SPI is guaranteed available until released by a call to {@link * SecurityParameterIndex#close()}. * * @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 * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated * 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. * *
If successful, this SPI is guaranteed available until released by a call to {@link * SecurityParameterIndex#close()}. * * @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 requestedSpi the requested SPI, or '0' to allocate a random SPI. + * @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 * @return the reserved SecurityParameterIndex * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated * for this user + * @throws SpiUnavailableException indicating that the requested SPI could not be reserved */ public SecurityParameterIndex reserveSecurityParameterIndex( 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 - * 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 - * address associated with that transform will throw an IOException. In addition, if the - * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to - * send() or receive() until the transform is removed from the socket by calling {@link - * #removeTransportModeTransform(Socket, IpSecTransform)}; + * Apply an IPsec transform to a stream socket. + * + *
This applies transport mode encapsulation to the given socket. Once applied, I/O on the + * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When + * the transform is removed from the socket by calling {@link #removeTransportModeTransform}, + * unprotected traffic can resume on that socket. + * + *
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}. + * + *
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 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 */ 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 - * 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 - * address associated with that transform will throw an IOException. In addition, if the - * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to - * send() or receive() until the transform is removed from the socket by calling {@link - * #removeTransportModeTransform(DatagramSocket, IpSecTransform)}; + * Apply an IPsec transform to a datagram socket. + * + *
This applies transport mode encapsulation to the given socket. Once applied, I/O on the + * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When + * the transform is removed from the socket by calling {@link #removeTransportModeTransform}, + * unprotected traffic can resume on that socket. + * + *
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}. + * + *
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 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 */ 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 - * 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 - * address associated with that transform will throw an IOException. In addition, if the - * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to - * send() or receive() until the transform is removed from the socket by calling {@link - * #removeTransportModeTransform(FileDescriptor, IpSecTransform)}; + * Apply an IPsec transform to a socket. + * + *
This applies transport mode encapsulation to the given socket. Once applied, I/O on the + * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When + * the transform is removed from the socket by calling {@link #removeTransportModeTransform}, + * unprotected traffic can resume on that socket. + * + *
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}. + * + *
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 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) throws IOException { @@ -323,6 +379,7 @@ public final class IpSecManager { * Applications should probably not use this API directly. Instead, they should use {@link * 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 transform an {@link IpSecTransform}, which must be an active Tunnel Mode transform. * @hide @@ -330,14 +387,19 @@ public final class IpSecManager { public void applyTunnelModeTransform(Network net, IpSecTransform transform) {} /** - * Remove a transform from a given stream socket. Once removed, traffic on the socket will not - * 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. + * Remove an IPsec transform from a stream socket. * - * @param socket a socket that previously had a transform applied to it. + *
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. + * + *
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 + * @throws IOException indicating that the transform could not be removed from the socket * @hide */ 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 - * 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. + * Remove an IPsec transform from a datagram socket. * - * @param socket a socket that previously had a transform applied to it. + *
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. + * + *
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 + * @throws IOException indicating that the transform could not be removed from the socket * @hide */ 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 - * 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. + * Remove an IPsec transform from a socket. * - * @param socket a socket file descriptor that previously had a transform applied to it. + *
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. + * + *
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 + * @throws IOException indicating that the transform could not be removed from the socket */ public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform) 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) { try { 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 * 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 transform a Tunnel Mode IPsec Transform that has been previously applied to the given * network @@ -405,11 +478,18 @@ public final class IpSecManager { public void removeTunnelModeTransform(Network net, IpSecTransform transform) {} /** - * Class providing access to a system-provided UDP Encapsulation Socket, which may be used for - * IKE signalling as well as for inbound and outbound UDP encapsulated IPsec traffic. + * This class provides access to a UDP encapsulation Socket. * - *
The socket provided by this class cannot be re-bound or closed via the inner - * FileDescriptor. Instead, disposing of this socket requires a call to close(). + *
{@code UdpEncapsulationSocket} wraps a system-provided datagram socket intended for IKEv2 + * 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. + * + *
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 { private final ParcelFileDescriptor mPfd; @@ -443,7 +523,7 @@ public final class IpSecManager { mCloseGuard.open("constructor"); } - /** Access the inner UDP Encapsulation Socket */ + /** Get the wrapped socket. */ public FileDescriptor getSocket() { if (mPfd == null) { return null; @@ -451,22 +531,19 @@ public final class IpSecManager { return mPfd.getFileDescriptor(); } - /** Retrieve the port number of the inner encapsulation socket */ + /** Get the bound port of the wrapped socket. */ public int getPort() { return mPort; } - @Override /** - * Release the resources that have been reserved for this Socket. + * Close this socket. * - *
This method closes the underlying socket, reducing a user's allocated sockets in the - * system. This must be done as part of cleanup following use of a socket. Failure to do so - * will cause the socket to count against a total allocation limit for IpSec and eventually - * fail due to resource limits. - * - * @param fd a file descriptor previously returned as a UDP Encapsulation socket. + *
This closes the wrapped socket. Open encapsulation sockets count against a user's + * resource limits, and forgetting to close them eventually will result in {@link + * ResourceUnavailableException} being thrown. */ + @Override public void close() throws IOException { try { mService.closeUdpEncapsulationSocket(mResourceId); @@ -483,6 +560,7 @@ public final class IpSecManager { mCloseGuard.close(); } + /** Check that the socket was closed properly. */ @Override protected void finalize() throws Throwable { 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. * - *
By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by - * the caller. This provides safe access to a socket on a port that can later be used as a UDP - * Encapsulation port. + *
See {@link UdpEncapsulationSocket} for the proper way to close the returned socket. * - *
This socket reservation works in conjunction with IpSecTransforms, which may re-use the - * socket port. Explicitly opening this port is only necessary if communication is desired on - * that port. - * - * @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. + * @param port a local UDP port + * @return a socket that is bound to the given 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 // 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. * - *
By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by - * the caller. This provides safe access to a socket on a port that can later be used as a UDP - * Encapsulation port. + *
See {@link UdpEncapsulationSocket} for the proper way to close the returned socket. * - *
This socket reservation works in conjunction with IpSecTransforms, which may re-use the - * socket port. Explicitly opening this port is only necessary if communication is desired on - * that port. + *
The local port of the returned socket can be obtained by calling {@link + * UdpEncapsulationSocket#getPort()}. * - * @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 // 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 * @hide diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 48b5bd5c3d..cda4ec762c 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -38,27 +38,29 @@ import java.lang.annotation.RetentionPolicy; 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. * - *
IpSecTransforms must be built from an IpSecTransform.Builder, and they must persist throughout - * the lifetime of the underlying transform. If a transform object leaves scope, the underlying - * transform may be disabled automatically, with likely undesirable results. + *
Transforms are created using {@link IpSecTransform.Builder}. Each {@code IpSecTransform} + * object encapsulates the properties and state of an inbound and outbound IPsec security + * association. That includes, but is not limited to, algorithm choice, key material, and allocated + * system resources. * - *
An IpSecTransform may either represent a tunnel mode transform that operates on a wide array - * of traffic or may represent a transport mode transform operating on a Socket or Sockets. + * @see RFC 4301, Security Architecture for the + * Internet Protocol */ public final class IpSecTransform implements AutoCloseable { private static final String TAG = "IpSecTransform"; /** - * For direction-specific attributes of an IpSecTransform, indicates that an attribute applies - * to traffic towards the host. + * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute + * applies to traffic towards the host. */ public static final int DIRECTION_IN = 0; /** - * For direction-specific attributes of an IpSecTransform, indicates that an attribute applies - * to traffic from the host. + * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute + * applies to traffic from the host. */ public static final int DIRECTION_OUT = 1; @@ -77,16 +79,16 @@ public final class IpSecTransform implements AutoCloseable { public static final int ENCAP_NONE = 0; /** - * IpSec traffic will be encapsulated within a UDP header with an additional 8-byte header pad - * (of '0'-value bytes) that prevents traffic from being interpreted as IKE or as ESP over UDP. + * IPsec traffic will be encapsulated within UDP, but with 8 zero-value bytes between the UDP + * header and payload. This prevents traffic from being interpreted as ESP or IKEv2. * * @hide */ public static final int ENCAP_ESPINUDP_NON_IKE = 1; /** - * IpSec traffic will be encapsulated within UDP as per RFC3498. + * IPsec traffic will be encapsulated within UDP as per + * RFC 3498. * * @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 - * the system for this Transform. + * Deactivate this {@code IpSecTransform} and free allocated resources. * - *
Deactivating a transform while it is still applied to any Socket will result in sockets - * refusing to send or receive data. This method will silently succeed if the specified - * transform has already been removed; thus, it is always safe to attempt cleanup when a - * transform is no longer needed. + *
Deactivating a transform while it is still applied to a socket will result in errors on + * that socket. Make sure to remove transforms by calling {@link + * IpSecManager#removeTransportModeTransform}. Note, removing an {@code IpSecTransform} from a + * socket will not deactivate it (because one transform may be applied to multiple sockets). + * + *
It is safe to call this method on a transform that has already been deactivated. */ public void close() { 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 protected void finalize() throws Throwable { if (mCloseGuard != null) { @@ -264,65 +268,63 @@ public final class IpSecTransform implements AutoCloseable { } /** - * Builder object to facilitate the creation of IpSecTransform objects. - * - *
Apply additional properties to the transform and then call a build() method to return an - * IpSecTransform object. - * - * @see Builder#buildTransportModeTransform(InetAddress) + * This class is used to build {@link IpSecTransform} objects. */ public static class Builder { private Context mContext; private IpSecConfig mConfig; /** - * Add an encryption algorithm to the transform for the given direction. + * Set the encryption algorithm for the given direction. * - *
If encryption is set for a given direction without also providing an SPI for that - * direction, creation of an IpSecTransform will fail upon calling a build() method. + *
If encryption is set for a direction without also providing an SPI for that direction, + * creation of an {@code IpSecTransform} will fail when attempting to build the transform. * - *
Authenticated encryption is mutually exclusive with encryption and authentication. + *
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. */ public IpSecTransform.Builder setEncryption( @TransformDirection int direction, IpSecAlgorithm algo) { + // TODO: throw IllegalArgumentException if algo is not an encryption algorithm. mConfig.setEncryption(direction, algo); return this; } /** - * Add an authentication/integrity algorithm to the transform. + * Set the authentication (integrity) algorithm for the given direction. * - *
If authentication is set for a given direction without also providing an SPI for that - * direction, creation of an IpSecTransform will fail upon calling a build() method. + *
If authentication is set for a direction without also providing an SPI for that + * direction, creation of an {@code IpSecTransform} will fail when attempting to build the + * transform. * - *
Authenticated encryption is mutually exclusive with encryption and authentication. + *
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. */ public IpSecTransform.Builder setAuthentication( @TransformDirection int direction, IpSecAlgorithm algo) { + // TODO: throw IllegalArgumentException if algo is not an authentication algorithm. mConfig.setAuthentication(direction, algo); return this; } /** - * Add an authenticated encryption algorithm to the transform for the given direction. + * Set the authenticated encryption algorithm for the given direction. * *
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 - * a build() method. + * providing an SPI for that direction, creation of an {@code IpSecTransform} will fail when + * attempting to build the transform. * *
The Authenticated Encryption (AE) class of algorithms are also known as Authenticated * Encryption with Associated Data (AEAD) algorithms, or Combined mode algorithms (as - * referred to in RFC 4301) + * referred to in RFC 4301). * *
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 * 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 - * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a - * given destination address. + * Set the SPI for the given direction. * - *
Care should be chosen when selecting an SPI to ensure that is is as unique as - * possible. To reserve a value call {@link IpSecManager#reserveSecurityParameterIndex(int, - * InetAddress, int)}. Otherwise, SPI collisions would prevent a transform from being - * activated. IpSecManager#reserveSecurityParameterIndex(int, InetAddres$s, int)}. + *
Because IPsec operates at the IP layer, this 32-bit identifier uniquely identifies + * packets to a given destination address. To prevent SPI collisions, values should be + * reserved by calling {@link IpSecManager#reserveSecurityParameterIndex}. * - *
Unless an SPI is set for a given direction, traffic in that direction will be - * sent/received without any IPsec applied. + *
If the SPI and algorithms are omitted for one direction, traffic in that direction + * 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 * 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 - * emit on the default network). + * Set the {@link Network} which will carry tunneled traffic. * - *
Restricts the transformed traffic to a particular {@link Network}. This is required in - * tunnel mode. + *
Restricts the transformed traffic to a particular {@link Network}. This is required + * for tunnel mode, otherwise tunneled traffic would be sent on the default network. * * @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. * - *
This option allows IPsec traffic to pass through NAT. Refer to RFC 3947 and 3948 for - * details on how UDP should be applied to IPsec. + *
This allows IPsec traffic to pass through a NAT. * - * @param localSocket a {@link IpSecManager.UdpEncapsulationSocket} for sending and - * receiving encapsulating traffic. - * @param remotePort the UDP port number of the remote that will send and receive - * encapsulated traffic. In the case of IKE, this is likely port 4500. + * @see RFC 3948, UDP Encapsulation of IPsec + * ESP Packets + * @see RFC 7296 section 2.23, + * NAT Traversal of IKEv2 + * + * @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( 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: Specify the needed NATT keepalive permission. /** - * Send a NATT Keepalive packet with a given maximum interval. This will create an offloaded - * 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. + * Set NAT-T keepalives to be sent with a given interval. + * + *
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 */ @SystemApi @@ -408,36 +412,29 @@ public final class IpSecTransform implements AutoCloseable { } /** - * Build and return an active {@link IpSecTransform} object as a Transport Mode Transform. - * 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. + * Build a transport mode {@link IpSecTransform}. * - *
Upon a successful return from this call, the provided IpSecTransform will be active - * and may be applied to sockets. If too many IpSecTransform objects are active for a given - * 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. + *
This builds and activates a transport mode transform. Note that an active transform + * will not affect any network traffic until it has been applied to one or more sockets. * - * @param remoteAddress the {@link InetAddress} that, when matched on traffic to/from this - * socket will cause the transform to be applied. - *
Note that an active transform will not impact any network traffic until it has - * been applied to one or more Sockets. Calling this method is a necessary precondition - * for applying it to a socket, but is not sufficient to actually apply IPsec. + * @see IpSecManager#applyTransportModeTransform + * + * @param remoteAddress the remote {@code InetAddress} of traffic on sockets that will use + * this transform * @throws IllegalArgumentException indicating that a particular combination of transform - * properties is invalid. - * @throws IpSecManager.ResourceUnavailableException in the event that no more Transforms - * may be allocated - * @throws SpiUnavailableException if the SPI collides with an existing transform - * (unlikely). - * @throws ResourceUnavailableException if the current user currently has exceeded the - * number of allowed active transforms. + * properties is invalid + * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms are + * active + * @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI + * collides with an existing transform + * @throws IOException indicating other errors */ public IpSecTransform buildTransportModeTransform(InetAddress remoteAddress) throws IpSecManager.ResourceUnavailableException, IpSecManager.SpiUnavailableException, IOException { mConfig.setMode(MODE_TRANSPORT); mConfig.setRemoteAddress(remoteAddress.getHostAddress()); + // FIXME: modifying a builder after calling build can change the built transform. 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) { Preconditions.checkNotNull(context);