Merge changes from topic "ipsec-oneway-transform"

* changes:
  Update IpSecService UnitTests
  Make Transforms Unidirectional
This commit is contained in:
nharold
2018-01-17 08:40:37 +00:00
committed by Gerrit Code Review
11 changed files with 491 additions and 702 deletions

View File

@@ -25814,12 +25814,18 @@ package android.net {
} }
public final class IpSecManager { public final class IpSecManager {
method public android.net.IpSecManager.SecurityParameterIndex allocateSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException; method public android.net.IpSecManager.SecurityParameterIndex allocateSecurityParameterIndex(java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
method public android.net.IpSecManager.SecurityParameterIndex allocateSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException; method public android.net.IpSecManager.SecurityParameterIndex allocateSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
method public void applyTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException; method public void applyTransportModeTransform(java.net.Socket, int, android.net.IpSecTransform) throws java.io.IOException;
method public void applyTransportModeTransform(java.net.DatagramSocket, int, android.net.IpSecTransform) throws java.io.IOException;
method public void applyTransportModeTransform(java.io.FileDescriptor, int, android.net.IpSecTransform) throws java.io.IOException;
method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException; method public void removeTransportModeTransforms(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
method public void removeTransportModeTransforms(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
method public void removeTransportModeTransforms(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;
field public static final int DIRECTION_IN = 0; // 0x0
field public static final int DIRECTION_OUT = 1; // 0x1
} }
public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException { public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
@@ -25842,18 +25848,15 @@ package android.net {
public final class IpSecTransform implements java.lang.AutoCloseable { public final class IpSecTransform implements java.lang.AutoCloseable {
method public void close(); method public void close();
field public static final int DIRECTION_IN = 0; // 0x0
field public static final int DIRECTION_OUT = 1; // 0x1
} }
public static class IpSecTransform.Builder { public static class IpSecTransform.Builder {
ctor public IpSecTransform.Builder(android.content.Context); ctor public IpSecTransform.Builder(android.content.Context);
method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException; method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress, android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
method public android.net.IpSecTransform.Builder setAuthenticatedEncryption(int, android.net.IpSecAlgorithm); method public android.net.IpSecTransform.Builder setAuthenticatedEncryption(android.net.IpSecAlgorithm);
method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm); method public android.net.IpSecTransform.Builder setAuthentication(android.net.IpSecAlgorithm);
method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm); method public android.net.IpSecTransform.Builder setEncryption(android.net.IpSecAlgorithm);
method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int); method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
} }
public class LinkAddress implements android.os.Parcelable { public class LinkAddress implements android.os.Parcelable {

View File

@@ -31,7 +31,7 @@ import android.os.ParcelFileDescriptor;
interface IIpSecService interface IIpSecService
{ {
IpSecSpiResponse allocateSecurityParameterIndex( IpSecSpiResponse allocateSecurityParameterIndex(
int direction, in String remoteAddress, int requestedSpi, in IBinder binder); in String destinationAddress, int requestedSpi, in IBinder binder);
void releaseSecurityParameterIndex(int resourceId); void releaseSecurityParameterIndex(int resourceId);
@@ -43,7 +43,7 @@ interface IIpSecService
void deleteTransportModeTransform(int transformId); void deleteTransportModeTransform(int transformId);
void applyTransportModeTransform(in ParcelFileDescriptor socket, int transformId); void applyTransportModeTransform(in ParcelFileDescriptor socket, int direction, int transformId);
void removeTransportModeTransform(in ParcelFileDescriptor socket, int transformId); void removeTransportModeTransforms(in ParcelFileDescriptor socket, int transformId);
} }

View File

@@ -256,13 +256,19 @@ public final class IpSecAlgorithm implements Parcelable {
return getName().equals(AUTH_CRYPT_AES_GCM); return getName().equals(AUTH_CRYPT_AES_GCM);
} }
// Because encryption keys are sensitive and userdebug builds are used by large user pools
// such as beta testers, we only allow sensitive info such as keys on eng builds.
private static boolean isUnsafeBuild() {
return Build.IS_DEBUGGABLE && Build.IS_ENG;
}
@Override @Override
public String toString() { public String toString() {
return new StringBuilder() return new StringBuilder()
.append("{mName=") .append("{mName=")
.append(mName) .append(mName)
.append(", mKey=") .append(", mKey=")
.append(Build.IS_DEBUGGABLE ? HexDump.toHexString(mKey) : "<hidden>") .append(isUnsafeBuild() ? HexDump.toHexString(mKey) : "<hidden>")
.append(", mTruncLenBits=") .append(", mTruncLenBits=")
.append(mTruncLenBits) .append(mTruncLenBits)
.append("}") .append("}")

View File

@@ -32,24 +32,19 @@ public final class IpSecConfig implements Parcelable {
// MODE_TRANSPORT or MODE_TUNNEL // MODE_TRANSPORT or MODE_TUNNEL
private int mMode = IpSecTransform.MODE_TRANSPORT; private int mMode = IpSecTransform.MODE_TRANSPORT;
// Needs to be valid only for tunnel mode
// Preventing this from being null simplifies Java->Native binder // Preventing this from being null simplifies Java->Native binder
private String mLocalAddress = ""; private String mSourceAddress = "";
// Preventing this from being null simplifies Java->Native binder // Preventing this from being null simplifies Java->Native binder
private String mRemoteAddress = ""; private String mDestinationAddress = "";
// The underlying Network that represents the "gateway" Network // The underlying Network that represents the "gateway" Network
// 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 {
// Minimum requirements for identifying a transform // Minimum requirements for identifying a transform
// SPI identifying the IPsec flow in packet processing // SPI identifying the IPsec SA in packet processing
// and a remote IP address // and a destination IP address
private int mSpiResourceId = IpSecManager.INVALID_RESOURCE_ID; private int mSpiResourceId = IpSecManager.INVALID_RESOURCE_ID;
// Encryption Algorithm // Encryption Algorithm
@@ -61,31 +56,6 @@ public final class IpSecConfig implements Parcelable {
// Authenticated Encryption Algorithm // Authenticated Encryption Algorithm
private IpSecAlgorithm mAuthenticatedEncryption; private IpSecAlgorithm mAuthenticatedEncryption;
@Override
public String toString() {
return new StringBuilder()
.append("{mSpiResourceId=")
.append(mSpiResourceId)
.append(", mEncryption=")
.append(mEncryption)
.append(", mAuthentication=")
.append(mAuthentication)
.append(", mAuthenticatedEncryption=")
.append(mAuthenticatedEncryption)
.append("}")
.toString();
}
static boolean equals(IpSecConfig.Flow lhs, IpSecConfig.Flow rhs) {
if (lhs == null || rhs == null) return (lhs == rhs);
return (lhs.mSpiResourceId == rhs.mSpiResourceId
&& IpSecAlgorithm.equals(lhs.mEncryption, rhs.mEncryption)
&& IpSecAlgorithm.equals(lhs.mAuthentication, rhs.mAuthentication));
}
}
private final Flow[] mFlow = new Flow[] {new Flow(), new Flow()};
// For tunnel mode IPv4 UDP Encapsulation // For tunnel mode IPv4 UDP Encapsulation
// IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE // IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE
private int mEncapType = IpSecTransform.ENCAP_NONE; private int mEncapType = IpSecTransform.ENCAP_NONE;
@@ -100,36 +70,37 @@ public final class IpSecConfig implements Parcelable {
mMode = mode; mMode = mode;
} }
/** Set the local IP address for Tunnel mode */ /** Set the source IP addres for this IPsec transform */
public void setLocalAddress(String localAddress) { public void setSourceAddress(String sourceAddress) {
mLocalAddress = localAddress; mSourceAddress = sourceAddress;
} }
/** Set the remote IP address for this IPsec transform */ /** Set the destination IP address for this IPsec transform */
public void setRemoteAddress(String remoteAddress) { public void setDestinationAddress(String destinationAddress) {
mRemoteAddress = remoteAddress; mDestinationAddress = destinationAddress;
} }
/** Set the SPI for a given direction by resource ID */ /** Set the SPI by resource ID */
public void setSpiResourceId(int direction, int resourceId) { public void setSpiResourceId(int resourceId) {
mFlow[direction].mSpiResourceId = resourceId; mSpiResourceId = resourceId;
} }
/** Set the encryption algorithm for a given direction */ /** Set the encryption algorithm */
public void setEncryption(int direction, IpSecAlgorithm encryption) { public void setEncryption(IpSecAlgorithm encryption) {
mFlow[direction].mEncryption = encryption; mEncryption = encryption;
} }
/** Set the authentication algorithm for a given direction */ /** Set the authentication algorithm */
public void setAuthentication(int direction, IpSecAlgorithm authentication) { public void setAuthentication(IpSecAlgorithm authentication) {
mFlow[direction].mAuthentication = authentication; mAuthentication = authentication;
} }
/** Set the authenticated encryption algorithm for a given direction */ /** Set the authenticated encryption algorithm */
public void setAuthenticatedEncryption(int direction, IpSecAlgorithm authenticatedEncryption) { public void setAuthenticatedEncryption(IpSecAlgorithm authenticatedEncryption) {
mFlow[direction].mAuthenticatedEncryption = authenticatedEncryption; mAuthenticatedEncryption = authenticatedEncryption;
} }
/** Set the underlying network that will carry traffic for this transform */
public void setNetwork(Network network) { public void setNetwork(Network network) {
mNetwork = network; mNetwork = network;
} }
@@ -155,28 +126,28 @@ public final class IpSecConfig implements Parcelable {
return mMode; return mMode;
} }
public String getLocalAddress() { public String getSourceAddress() {
return mLocalAddress; return mSourceAddress;
} }
public int getSpiResourceId(int direction) { public int getSpiResourceId() {
return mFlow[direction].mSpiResourceId; return mSpiResourceId;
} }
public String getRemoteAddress() { public String getDestinationAddress() {
return mRemoteAddress; return mDestinationAddress;
} }
public IpSecAlgorithm getEncryption(int direction) { public IpSecAlgorithm getEncryption() {
return mFlow[direction].mEncryption; return mEncryption;
} }
public IpSecAlgorithm getAuthentication(int direction) { public IpSecAlgorithm getAuthentication() {
return mFlow[direction].mAuthentication; return mAuthentication;
} }
public IpSecAlgorithm getAuthenticatedEncryption(int direction) { public IpSecAlgorithm getAuthenticatedEncryption() {
return mFlow[direction].mAuthenticatedEncryption; return mAuthenticatedEncryption;
} }
public Network getNetwork() { public Network getNetwork() {
@@ -209,17 +180,13 @@ public final class IpSecConfig implements Parcelable {
@Override @Override
public void writeToParcel(Parcel out, int flags) { public void writeToParcel(Parcel out, int flags) {
out.writeInt(mMode); out.writeInt(mMode);
out.writeString(mLocalAddress); out.writeString(mSourceAddress);
out.writeString(mRemoteAddress); out.writeString(mDestinationAddress);
out.writeParcelable(mNetwork, flags); out.writeParcelable(mNetwork, flags);
out.writeInt(mFlow[IpSecTransform.DIRECTION_IN].mSpiResourceId); out.writeInt(mSpiResourceId);
out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mEncryption, flags); out.writeParcelable(mEncryption, flags);
out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mAuthentication, flags); out.writeParcelable(mAuthentication, flags);
out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mAuthenticatedEncryption, flags); out.writeParcelable(mAuthenticatedEncryption, flags);
out.writeInt(mFlow[IpSecTransform.DIRECTION_OUT].mSpiResourceId);
out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mEncryption, flags);
out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mAuthentication, flags);
out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mAuthenticatedEncryption, flags);
out.writeInt(mEncapType); out.writeInt(mEncapType);
out.writeInt(mEncapSocketResourceId); out.writeInt(mEncapSocketResourceId);
out.writeInt(mEncapRemotePort); out.writeInt(mEncapRemotePort);
@@ -231,22 +198,15 @@ public final class IpSecConfig implements Parcelable {
private IpSecConfig(Parcel in) { private IpSecConfig(Parcel in) {
mMode = in.readInt(); mMode = in.readInt();
mLocalAddress = in.readString(); mSourceAddress = in.readString();
mRemoteAddress = in.readString(); mDestinationAddress = in.readString();
mNetwork = (Network) in.readParcelable(Network.class.getClassLoader()); mNetwork = (Network) in.readParcelable(Network.class.getClassLoader());
mFlow[IpSecTransform.DIRECTION_IN].mSpiResourceId = in.readInt(); mSpiResourceId = in.readInt();
mFlow[IpSecTransform.DIRECTION_IN].mEncryption = mEncryption =
(IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
mFlow[IpSecTransform.DIRECTION_IN].mAuthentication = mAuthentication =
(IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
mFlow[IpSecTransform.DIRECTION_IN].mAuthenticatedEncryption = mAuthenticatedEncryption =
(IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
mFlow[IpSecTransform.DIRECTION_OUT].mSpiResourceId = in.readInt();
mFlow[IpSecTransform.DIRECTION_OUT].mEncryption =
(IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
mFlow[IpSecTransform.DIRECTION_OUT].mAuthentication =
(IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
mFlow[IpSecTransform.DIRECTION_OUT].mAuthenticatedEncryption =
(IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
mEncapType = in.readInt(); mEncapType = in.readInt();
mEncapSocketResourceId = in.readInt(); mEncapSocketResourceId = in.readInt();
@@ -260,10 +220,10 @@ public final class IpSecConfig implements Parcelable {
strBuilder strBuilder
.append("{mMode=") .append("{mMode=")
.append(mMode == IpSecTransform.MODE_TUNNEL ? "TUNNEL" : "TRANSPORT") .append(mMode == IpSecTransform.MODE_TUNNEL ? "TUNNEL" : "TRANSPORT")
.append(", mLocalAddress=") .append(", mSourceAddress=")
.append(mLocalAddress) .append(mSourceAddress)
.append(", mRemoteAddress=") .append(", mDestinationAddress=")
.append(mRemoteAddress) .append(mDestinationAddress)
.append(", mNetwork=") .append(", mNetwork=")
.append(mNetwork) .append(mNetwork)
.append(", mEncapType=") .append(", mEncapType=")
@@ -274,10 +234,14 @@ public final class IpSecConfig implements Parcelable {
.append(mEncapRemotePort) .append(mEncapRemotePort)
.append(", mNattKeepaliveInterval=") .append(", mNattKeepaliveInterval=")
.append(mNattKeepaliveInterval) .append(mNattKeepaliveInterval)
.append(", mFlow[OUT]=") .append("{mSpiResourceId=")
.append(mFlow[IpSecTransform.DIRECTION_OUT]) .append(mSpiResourceId)
.append(", mFlow[IN]=") .append(", mEncryption=")
.append(mFlow[IpSecTransform.DIRECTION_IN]) .append(mEncryption)
.append(", mAuthentication=")
.append(mAuthentication)
.append(", mAuthenticatedEncryption=")
.append(mAuthenticatedEncryption)
.append("}"); .append("}");
return strBuilder.toString(); return strBuilder.toString();
@@ -299,17 +263,18 @@ public final class IpSecConfig implements Parcelable {
public static boolean equals(IpSecConfig lhs, IpSecConfig rhs) { public static boolean equals(IpSecConfig lhs, IpSecConfig rhs) {
if (lhs == null || rhs == null) return (lhs == rhs); if (lhs == null || rhs == null) return (lhs == rhs);
return (lhs.mMode == rhs.mMode return (lhs.mMode == rhs.mMode
&& lhs.mLocalAddress.equals(rhs.mLocalAddress) && lhs.mSourceAddress.equals(rhs.mSourceAddress)
&& lhs.mRemoteAddress.equals(rhs.mRemoteAddress) && lhs.mDestinationAddress.equals(rhs.mDestinationAddress)
&& ((lhs.mNetwork != null && lhs.mNetwork.equals(rhs.mNetwork)) && ((lhs.mNetwork != null && lhs.mNetwork.equals(rhs.mNetwork))
|| (lhs.mNetwork == rhs.mNetwork)) || (lhs.mNetwork == rhs.mNetwork))
&& lhs.mEncapType == rhs.mEncapType && lhs.mEncapType == rhs.mEncapType
&& lhs.mEncapSocketResourceId == rhs.mEncapSocketResourceId && lhs.mEncapSocketResourceId == rhs.mEncapSocketResourceId
&& lhs.mEncapRemotePort == rhs.mEncapRemotePort && lhs.mEncapRemotePort == rhs.mEncapRemotePort
&& lhs.mNattKeepaliveInterval == rhs.mNattKeepaliveInterval && lhs.mNattKeepaliveInterval == rhs.mNattKeepaliveInterval
&& IpSecConfig.Flow.equals(lhs.mFlow[IpSecTransform.DIRECTION_OUT], && lhs.mSpiResourceId == rhs.mSpiResourceId
rhs.mFlow[IpSecTransform.DIRECTION_OUT]) && IpSecAlgorithm.equals(lhs.mEncryption, rhs.mEncryption)
&& IpSecConfig.Flow.equals(lhs.mFlow[IpSecTransform.DIRECTION_IN], && IpSecAlgorithm.equals(
rhs.mFlow[IpSecTransform.DIRECTION_IN])); lhs.mAuthenticatedEncryption, rhs.mAuthenticatedEncryption)
&& IpSecAlgorithm.equals(lhs.mAuthentication, rhs.mAuthentication));
} }
} }

View File

@@ -17,6 +17,7 @@ package android.net;
import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.IntDef;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.SystemService; import android.annotation.SystemService;
import android.annotation.TestApi; import android.annotation.TestApi;
@@ -33,6 +34,8 @@ import dalvik.system.CloseGuard;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.IOException; import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.DatagramSocket; import java.net.DatagramSocket;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.Socket; import java.net.Socket;
@@ -52,6 +55,23 @@ import java.net.Socket;
public final class IpSecManager { public final class IpSecManager {
private static final String TAG = "IpSecManager"; private static final String TAG = "IpSecManager";
/**
* 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 {@link IpSecTransform}, indicates that an attribute
* applies to traffic from the host.
*/
public static final int DIRECTION_OUT = 1;
/** @hide */
@IntDef(value = {DIRECTION_IN, DIRECTION_OUT})
@Retention(RetentionPolicy.SOURCE)
public @interface PolicyDirection {}
/** /**
* The Security Parameter Index (SPI) 0 indicates an unknown or invalid index. * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index.
* *
@@ -125,7 +145,7 @@ public final class IpSecManager {
*/ */
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 mDestinationAddress;
private final CloseGuard mCloseGuard = CloseGuard.get(); private final CloseGuard mCloseGuard = CloseGuard.get();
private int mSpi = INVALID_SECURITY_PARAMETER_INDEX; private int mSpi = INVALID_SECURITY_PARAMETER_INDEX;
private int mResourceId = INVALID_RESOURCE_ID; private int mResourceId = INVALID_RESOURCE_ID;
@@ -164,14 +184,14 @@ public final class IpSecManager {
} }
private SecurityParameterIndex( private SecurityParameterIndex(
@NonNull IIpSecService service, int direction, InetAddress remoteAddress, int spi) @NonNull IIpSecService service, InetAddress destinationAddress, int spi)
throws ResourceUnavailableException, SpiUnavailableException { throws ResourceUnavailableException, SpiUnavailableException {
mService = service; mService = service;
mRemoteAddress = remoteAddress; mDestinationAddress = destinationAddress;
try { try {
IpSecSpiResponse result = IpSecSpiResponse result =
mService.allocateSecurityParameterIndex( mService.allocateSecurityParameterIndex(
direction, remoteAddress.getHostAddress(), spi, new Binder()); destinationAddress.getHostAddress(), spi, new Binder());
if (result == null) { if (result == null) {
throw new NullPointerException("Received null response from IpSecService"); throw new NullPointerException("Received null response from IpSecService");
@@ -216,25 +236,23 @@ public final class IpSecManager {
} }
/** /**
* Reserve a random SPI for traffic bound to or from the specified remote address. * Reserve a random SPI for traffic bound to or from the specified destination 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 destinationAddress the destination address for traffic bearing the requested SPI.
* @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress * For inbound traffic, the destination should be an address currently assigned on-device.
* @return the reserved SecurityParameterIndex * @return the reserved SecurityParameterIndex
* @throws ResourceUnavailableException indicating that too many SPIs are currently allocated * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are
* for this user * currently allocated for this user
* @throws SpiUnavailableException indicating that a particular SPI cannot be reserved
*/ */
public SecurityParameterIndex allocateSecurityParameterIndex( public SecurityParameterIndex allocateSecurityParameterIndex(InetAddress destinationAddress)
int direction, InetAddress remoteAddress) throws ResourceUnavailableException { throws ResourceUnavailableException {
try { try {
return new SecurityParameterIndex( return new SecurityParameterIndex(
mService, mService,
direction, destinationAddress,
remoteAddress,
IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
} catch (SpiUnavailableException unlikely) { } catch (SpiUnavailableException unlikely) {
throw new ResourceUnavailableException("No SPIs available"); throw new ResourceUnavailableException("No SPIs available");
@@ -242,26 +260,27 @@ public final class IpSecManager {
} }
/** /**
* Reserve the requested SPI for traffic bound to or from the specified remote address. * Reserve the requested SPI for traffic bound to or from the specified destination 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 destinationAddress the destination address for traffic bearing the requested SPI.
* @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress * For inbound traffic, the destination should be an address currently assigned on-device.
* @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 {@link #ResourceUnavailableException} indicating that too many SPIs are
* for this user * currently allocated for this user
* @throws SpiUnavailableException indicating that the requested SPI could not be reserved * @throws {@link #SpiUnavailableException} indicating that the requested SPI could not be
* reserved
*/ */
public SecurityParameterIndex allocateSecurityParameterIndex( public SecurityParameterIndex allocateSecurityParameterIndex(
int direction, InetAddress remoteAddress, int requestedSpi) InetAddress destinationAddress, int requestedSpi)
throws SpiUnavailableException, ResourceUnavailableException { throws SpiUnavailableException, ResourceUnavailableException {
if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) { if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) {
throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI"); throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI");
} }
return new SecurityParameterIndex(mService, direction, remoteAddress, requestedSpi); return new SecurityParameterIndex(mService, destinationAddress, requestedSpi);
} }
/** /**
@@ -269,14 +288,14 @@ public final class IpSecManager {
* *
* <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the * <p>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 * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
* the transform is removed from the socket by calling {@link #removeTransportModeTransform}, * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
* unprotected traffic can resume on that socket. * unprotected traffic can resume on that socket.
* *
* <p>For security reasons, the destination address of any traffic on the socket must match the * <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 * 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 * 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 * will throw IOException if the user deactivates the transform (by calling {@link
* IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}. * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
* *
* <h4>Rekey Procedure</h4> * <h4>Rekey Procedure</h4>
* *
@@ -287,14 +306,15 @@ public final class IpSecManager {
* in-flight packets have been received. * in-flight packets have been received.
* *
* @param socket a stream socket * @param socket a stream socket
* @param direction the policy direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT}
* @param transform a transport mode {@code IpSecTransform} * @param transform a transport mode {@code IpSecTransform}
* @throws IOException indicating that the transform could not be applied * @throws IOException indicating that the transform could not be applied
* @hide
*/ */
public void applyTransportModeTransform(Socket socket, IpSecTransform transform) public void applyTransportModeTransform(
Socket socket, int direction, IpSecTransform transform)
throws IOException { throws IOException {
try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket)) { try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket)) {
applyTransportModeTransform(pfd, transform); applyTransportModeTransform(pfd, direction, transform);
} }
} }
@@ -303,14 +323,14 @@ public final class IpSecManager {
* *
* <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the * <p>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 * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
* the transform is removed from the socket by calling {@link #removeTransportModeTransform}, * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
* unprotected traffic can resume on that socket. * unprotected traffic can resume on that socket.
* *
* <p>For security reasons, the destination address of any traffic on the socket must match the * <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 * 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 * 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 * will throw IOException if the user deactivates the transform (by calling {@link
* IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}. * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
* *
* <h4>Rekey Procedure</h4> * <h4>Rekey Procedure</h4>
* *
@@ -321,14 +341,14 @@ public final class IpSecManager {
* in-flight packets have been received. * in-flight packets have been received.
* *
* @param socket a datagram socket * @param socket a datagram socket
* @param direction the policy direction either DIRECTION_IN or DIRECTION_OUT
* @param transform a transport mode {@code IpSecTransform} * @param transform a transport mode {@code IpSecTransform}
* @throws IOException indicating that the transform could not be applied * @throws IOException indicating that the transform could not be applied
* @hide
*/ */
public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform) public void applyTransportModeTransform(
throws IOException { DatagramSocket socket, int direction, IpSecTransform transform) throws IOException {
try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket)) { try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket)) {
applyTransportModeTransform(pfd, transform); applyTransportModeTransform(pfd, direction, transform);
} }
} }
@@ -337,14 +357,14 @@ public final class IpSecManager {
* *
* <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the * <p>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 * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
* the transform is removed from the socket by calling {@link #removeTransportModeTransform}, * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
* unprotected traffic can resume on that socket. * unprotected traffic can resume on that socket.
* *
* <p>For security reasons, the destination address of any traffic on the socket must match the * <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 * 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 * 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 * will throw IOException if the user deactivates the transform (by calling {@link
* IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}. * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
* *
* <h4>Rekey Procedure</h4> * <h4>Rekey Procedure</h4>
* *
@@ -355,24 +375,27 @@ public final class IpSecManager {
* in-flight packets have been received. * in-flight packets have been received.
* *
* @param socket a socket file descriptor * @param socket a socket file descriptor
* @param direction the policy direction either DIRECTION_IN or DIRECTION_OUT
* @param transform a transport mode {@code IpSecTransform} * @param transform a transport mode {@code IpSecTransform}
* @throws IOException indicating that the transform could not be applied * @throws IOException indicating that the transform could not be applied
*/ */
public void applyTransportModeTransform(FileDescriptor socket, IpSecTransform transform) public void applyTransportModeTransform(
FileDescriptor socket, int direction, IpSecTransform transform)
throws IOException { throws IOException {
// We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor() // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor()
// constructor takes control and closes the user's FD when we exit the method // constructor takes control and closes the user's FD when we exit the method
// This is behaviorally the same as the other versions, but the PFD constructor does not // This is behaviorally the same as the other versions, but the PFD constructor does not
// dup() automatically, whereas PFD.fromSocket() and PDF.fromDatagramSocket() do dup(). // dup() automatically, whereas PFD.fromSocket() and PDF.fromDatagramSocket() do dup().
try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
applyTransportModeTransform(pfd, transform); applyTransportModeTransform(pfd, direction, transform);
} }
} }
/* Call down to activate a transform */ /* Call down to activate a transform */
private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { private void applyTransportModeTransform(
ParcelFileDescriptor pfd, int direction, IpSecTransform transform) throws IOException {
try { try {
mService.applyTransportModeTransform(pfd, transform.getResourceId()); mService.applyTransportModeTransform(pfd, direction, transform.getResourceId());
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }
@@ -407,12 +430,11 @@ public final class IpSecManager {
* @param socket a socket that previously had a transform applied to it * @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 * @throws IOException indicating that the transform could not be removed from the socket
* @hide
*/ */
public void removeTransportModeTransform(Socket socket, IpSecTransform transform) public void removeTransportModeTransforms(Socket socket, IpSecTransform transform)
throws IOException { throws IOException {
try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket)) { try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket)) {
removeTransportModeTransform(pfd, transform); removeTransportModeTransforms(pfd, transform);
} }
} }
@@ -430,12 +452,11 @@ public final class IpSecManager {
* @param socket a socket that previously had a transform applied to it * @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 * @throws IOException indicating that the transform could not be removed from the socket
* @hide
*/ */
public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform) public void removeTransportModeTransforms(DatagramSocket socket, IpSecTransform transform)
throws IOException { throws IOException {
try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket)) { try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket)) {
removeTransportModeTransform(pfd, transform); removeTransportModeTransforms(pfd, transform);
} }
} }
@@ -454,17 +475,17 @@ public final class IpSecManager {
* @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 * @throws IOException indicating that the transform could not be removed from the socket
*/ */
public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform) public void removeTransportModeTransforms(FileDescriptor socket, IpSecTransform transform)
throws IOException { throws IOException {
try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
removeTransportModeTransform(pfd, transform); removeTransportModeTransforms(pfd, transform);
} }
} }
/* Call down to remove a transform */ /* Call down to remove a transform */
private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { private void removeTransportModeTransforms(ParcelFileDescriptor pfd, IpSecTransform transform) {
try { try {
mService.removeTransportModeTransform(pfd, transform.getResourceId()); mService.removeTransportModeTransforms(pfd, transform.getResourceId());
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }

View File

@@ -38,13 +38,11 @@ import java.lang.annotation.RetentionPolicy;
import java.net.InetAddress; import java.net.InetAddress;
/** /**
* This class represents an IPsec transform, which comprises security associations in one or both * This class represents a transform, which roughly corresponds to an IPsec Security Association.
* directions.
* *
* <p>Transforms are created using {@link IpSecTransform.Builder}. Each {@code IpSecTransform} * <p>Transforms are created using {@link IpSecTransform.Builder}. Each {@code IpSecTransform}
* object encapsulates the properties and state of an inbound and outbound IPsec security * object encapsulates the properties and state of an IPsec security association. That includes,
* association. That includes, but is not limited to, algorithm choice, key material, and allocated * but is not limited to, algorithm choice, key material, and allocated system resources.
* system resources.
* *
* @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
* Internet Protocol</a> * Internet Protocol</a>
@@ -52,23 +50,6 @@ import java.net.InetAddress;
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 {@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 {@link IpSecTransform}, indicates that an attribute
* applies to traffic from the host.
*/
public static final int DIRECTION_OUT = 1;
/** @hide */
@IntDef(value = {DIRECTION_IN, DIRECTION_OUT})
@Retention(RetentionPolicy.SOURCE)
public @interface TransformDirection {}
/** @hide */ /** @hide */
public static final int MODE_TRANSPORT = 0; public static final int MODE_TRANSPORT = 0;
@@ -170,7 +151,7 @@ public final class IpSecTransform implements AutoCloseable {
* *
* <p>Deactivating a transform while it is still applied to a socket will result in errors on * <p>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 * that socket. Make sure to remove transforms by calling {@link
* IpSecManager#removeTransportModeTransform}. Note, removing an {@code IpSecTransform} from a * IpSecManager#removeTransportModeTransforms}. Note, removing an {@code IpSecTransform} from a
* socket will not deactivate it (because one transform may be applied to multiple sockets). * 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. * <p>It is safe to call this method on a transform that has already been deactivated.
@@ -272,85 +253,49 @@ public final class IpSecTransform implements AutoCloseable {
private IpSecConfig mConfig; private IpSecConfig mConfig;
/** /**
* Set the encryption algorithm for the given direction. * Set the encryption algorithm.
*
* <p>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.
* *
* <p>Encryption is mutually exclusive with authenticated encryption. * <p>Encryption is mutually exclusive with authenticated encryption.
* *
* @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(@NonNull IpSecAlgorithm algo) {
@TransformDirection int direction, IpSecAlgorithm algo) {
// TODO: throw IllegalArgumentException if algo is not an encryption algorithm. // TODO: throw IllegalArgumentException if algo is not an encryption algorithm.
mConfig.setEncryption(direction, algo); Preconditions.checkNotNull(algo);
mConfig.setEncryption(algo);
return this; return this;
} }
/** /**
* Set the authentication (integrity) algorithm for the given direction. * Set the authentication (integrity) algorithm.
*
* <p>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.
* *
* <p>Authentication is mutually exclusive with authenticated encryption. * <p>Authentication is mutually exclusive with authenticated encryption.
* *
* @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(@NonNull IpSecAlgorithm algo) {
@TransformDirection int direction, IpSecAlgorithm algo) {
// TODO: throw IllegalArgumentException if algo is not an authentication algorithm. // TODO: throw IllegalArgumentException if algo is not an authentication algorithm.
mConfig.setAuthentication(direction, algo); Preconditions.checkNotNull(algo);
mConfig.setAuthentication(algo);
return this; return this;
} }
/** /**
* Set the authenticated encryption algorithm for the given direction. * Set the authenticated encryption algorithm.
* *
* <p>If an authenticated encryption algorithm is set for a given direction without also * <p>The Authenticated Encryption (AE) class of algorithms are also known as
* providing an SPI for that direction, creation of an {@code IpSecTransform} will fail when * Authenticated Encryption with Associated Data (AEAD) algorithms, or Combined mode
* attempting to build the transform. * algorithms (as referred to in
* * <a href="https://tools.ietf.org/html/rfc4301">RFC 4301</a>).
* <p>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 <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 {@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.
*/ */
public IpSecTransform.Builder setAuthenticatedEncryption( public IpSecTransform.Builder setAuthenticatedEncryption(@NonNull IpSecAlgorithm algo) {
@TransformDirection int direction, IpSecAlgorithm algo) { Preconditions.checkNotNull(algo);
mConfig.setAuthenticatedEncryption(direction, algo); mConfig.setAuthenticatedEncryption(algo);
return this;
}
/**
* Set the SPI for the given direction.
*
* <p>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#allocateSecurityParameterIndex}.
*
* <p>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 {@link #DIRECTION_OUT}
* @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed
* traffic
*/
public IpSecTransform.Builder setSpi(
@TransformDirection int direction, IpSecManager.SecurityParameterIndex spi) {
if (spi.getResourceId() == INVALID_RESOURCE_ID) {
throw new IllegalArgumentException("Invalid SecurityParameterIndex");
}
mConfig.setSpiResourceId(direction, spi.getResourceId());
return this; return this;
} }
@@ -363,7 +308,8 @@ public final class IpSecTransform implements AutoCloseable {
* @hide * @hide
*/ */
@SystemApi @SystemApi
public IpSecTransform.Builder setUnderlyingNetwork(Network net) { public IpSecTransform.Builder setUnderlyingNetwork(@NonNull Network net) {
Preconditions.checkNotNull(net);
mConfig.setNetwork(net); mConfig.setNetwork(net);
return this; return this;
} }
@@ -382,7 +328,8 @@ public final class IpSecTransform implements AutoCloseable {
* encapsulated traffic. In the case of IKEv2, this should be port 4500. * 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) { @NonNull IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) {
Preconditions.checkNotNull(localSocket);
mConfig.setEncapType(ENCAP_ESPINUDP); mConfig.setEncapType(ENCAP_ESPINUDP);
if (localSocket.getResourceId() == INVALID_RESOURCE_ID) { if (localSocket.getResourceId() == INVALID_RESOURCE_ID) {
throw new IllegalArgumentException("Invalid UdpEncapsulationSocket"); throw new IllegalArgumentException("Invalid UdpEncapsulationSocket");
@@ -419,24 +366,33 @@ public final class IpSecTransform implements AutoCloseable {
* will not affect any network traffic until it has been applied to one or more sockets. * will not affect any network traffic until it has been applied to one or more sockets.
* *
* @see IpSecManager#applyTransportModeTransform * @see IpSecManager#applyTransportModeTransform
* @param remoteAddress the remote {@code InetAddress} of traffic on sockets that will use * @param sourceAddress the source {@code InetAddress} of traffic on sockets that will use
* this transform * this transform; this address must belong to the Network used by all sockets that
* utilize this transform; if provided, then only traffic originating from the
* specified source address will be processed.
* @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed
* traffic
* @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 indicating that too many transforms are * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms
* active * are active
* @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI * @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI
* collides with an existing transform * collides with an existing transform
* @throws IOException indicating other errors * @throws IOException indicating other errors
*/ */
public IpSecTransform buildTransportModeTransform(InetAddress remoteAddress) public IpSecTransform buildTransportModeTransform(
@NonNull InetAddress sourceAddress,
@NonNull IpSecManager.SecurityParameterIndex spi)
throws IpSecManager.ResourceUnavailableException, throws IpSecManager.ResourceUnavailableException,
IpSecManager.SpiUnavailableException, IOException { IpSecManager.SpiUnavailableException, IOException {
if (remoteAddress == null) { Preconditions.checkNotNull(sourceAddress);
throw new IllegalArgumentException("Remote address may not be null or empty!"); Preconditions.checkNotNull(spi);
if (spi.getResourceId() == INVALID_RESOURCE_ID) {
throw new IllegalArgumentException("Invalid SecurityParameterIndex");
} }
mConfig.setMode(MODE_TRANSPORT); mConfig.setMode(MODE_TRANSPORT);
mConfig.setRemoteAddress(remoteAddress.getHostAddress()); mConfig.setSourceAddress(sourceAddress.getHostAddress());
mConfig.setSpiResourceId(spi.getResourceId());
// FIXME: modifying a builder after calling build can change the built transform. // FIXME: modifying a builder after calling build can change the built transform.
return new IpSecTransform(mContext, mConfig).activate(); return new IpSecTransform(mContext, mConfig).activate();
} }
@@ -445,26 +401,33 @@ public final class IpSecTransform implements AutoCloseable {
* Build and return an {@link IpSecTransform} object as a Tunnel Mode Transform. Some * Build and return an {@link IpSecTransform} object as a Tunnel Mode Transform. Some
* parameters have interdependencies that are checked at build time. * parameters have interdependencies that are checked at build time.
* *
* @param localAddress the {@link InetAddress} that provides the local endpoint for this * @param sourceAddress the {@link InetAddress} that provides the source address for this
* IPsec tunnel. This is almost certainly an address belonging to the {@link Network} * IPsec tunnel. This is almost certainly an address belonging to the {@link Network}
* that will originate the traffic, which is set as the {@link #setUnderlyingNetwork}. * that will originate the traffic, which is set as the {@link #setUnderlyingNetwork}.
* @param remoteAddress the {@link InetAddress} representing the remote endpoint of this * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed
* IPsec tunnel. * traffic
* @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 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
* @hide * @hide
*/ */
public IpSecTransform buildTunnelModeTransform( public IpSecTransform buildTunnelModeTransform(
InetAddress localAddress, InetAddress remoteAddress) { @NonNull InetAddress sourceAddress,
if (localAddress == null) { @NonNull IpSecManager.SecurityParameterIndex spi)
throw new IllegalArgumentException("Local address may not be null or empty!"); throws IpSecManager.ResourceUnavailableException,
IpSecManager.SpiUnavailableException, IOException {
Preconditions.checkNotNull(sourceAddress);
Preconditions.checkNotNull(spi);
if (spi.getResourceId() == INVALID_RESOURCE_ID) {
throw new IllegalArgumentException("Invalid SecurityParameterIndex");
} }
if (remoteAddress == null) {
throw new IllegalArgumentException("Remote address may not be null or empty!");
}
mConfig.setLocalAddress(localAddress.getHostAddress());
mConfig.setRemoteAddress(remoteAddress.getHostAddress());
mConfig.setMode(MODE_TUNNEL); mConfig.setMode(MODE_TUNNEL);
mConfig.setSourceAddress(sourceAddress.getHostAddress());
mConfig.setSpiResourceId(spi.getResourceId());
return new IpSecTransform(mContext, mConfig); return new IpSecTransform(mContext, mConfig);
} }

View File

@@ -25,6 +25,7 @@ import static android.system.OsConstants.SOCK_DGRAM;
import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.internal.util.Preconditions.checkNotNull;
import android.content.Context; import android.content.Context;
import android.net.ConnectivityManager;
import android.net.IIpSecService; import android.net.IIpSecService;
import android.net.INetd; import android.net.INetd;
import android.net.IpSecAlgorithm; import android.net.IpSecAlgorithm;
@@ -62,7 +63,6 @@ import java.net.InetSocketAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import libcore.io.IoUtils; import libcore.io.IoUtils;
@@ -83,7 +83,7 @@ public class IpSecService extends IIpSecService.Stub {
private static final String NETD_SERVICE_NAME = "netd"; private static final String NETD_SERVICE_NAME = "netd";
private static final int[] DIRECTIONS = private static final int[] DIRECTIONS =
new int[] {IpSecTransform.DIRECTION_OUT, IpSecTransform.DIRECTION_IN}; new int[] {IpSecManager.DIRECTION_OUT, IpSecManager.DIRECTION_IN};
private static final int NETD_FETCH_TIMEOUT_MS = 5000; // ms private static final int NETD_FETCH_TIMEOUT_MS = 5000; // ms
private static final int MAX_PORT_BIND_ATTEMPTS = 10; private static final int MAX_PORT_BIND_ATTEMPTS = 10;
@@ -104,10 +104,10 @@ public class IpSecService extends IIpSecService.Stub {
private final Context mContext; private final Context mContext;
/** /**
* The next non-repeating global ID for tracking resources between users, this service, * The next non-repeating global ID for tracking resources between users, this service, and
* and kernel data structures. Accessing this variable is not thread safe, so it is * kernel data structures. Accessing this variable is not thread safe, so it is only read or
* only read or modified within blocks synchronized on IpSecService.this. We want to * modified within blocks synchronized on IpSecService.this. We want to avoid -1
* avoid -1 (INVALID_RESOURCE_ID) and 0 (we probably forgot to initialize it). * (INVALID_RESOURCE_ID) and 0 (we probably forgot to initialize it).
*/ */
@GuardedBy("IpSecService.this") @GuardedBy("IpSecService.this")
private int mNextResourceId = 1; private int mNextResourceId = 1;
@@ -536,14 +536,14 @@ public class IpSecService extends IIpSecService.Stub {
private final class TransformRecord extends KernelResourceRecord { private final class TransformRecord extends KernelResourceRecord {
private final IpSecConfig mConfig; private final IpSecConfig mConfig;
private final SpiRecord[] mSpis; private final SpiRecord mSpi;
private final EncapSocketRecord mSocket; private final EncapSocketRecord mSocket;
TransformRecord( TransformRecord(
int resourceId, IpSecConfig config, SpiRecord[] spis, EncapSocketRecord socket) { int resourceId, IpSecConfig config, SpiRecord spi, EncapSocketRecord socket) {
super(resourceId); super(resourceId);
mConfig = config; mConfig = config;
mSpis = spis; mSpi = spi;
mSocket = socket; mSocket = socket;
} }
@@ -551,30 +551,27 @@ public class IpSecService extends IIpSecService.Stub {
return mConfig; return mConfig;
} }
public SpiRecord getSpiRecord(int direction) { public SpiRecord getSpiRecord() {
return mSpis[direction]; return mSpi;
} }
/** always guarded by IpSecService#this */ /** always guarded by IpSecService#this */
@Override @Override
public void freeUnderlyingResources() { public void freeUnderlyingResources() {
for (int direction : DIRECTIONS) { int spi = mSpi.getSpi();
int spi = mSpis[direction].getSpi();
try { try {
mSrvConfig mSrvConfig
.getNetdInstance() .getNetdInstance()
.ipSecDeleteSecurityAssociation( .ipSecDeleteSecurityAssociation(
mResourceId, mResourceId,
direction, mConfig.getSourceAddress(),
mConfig.getLocalAddress(), mConfig.getDestinationAddress(),
mConfig.getRemoteAddress(),
spi); spi);
} catch (ServiceSpecificException e) { } catch (ServiceSpecificException e) {
// FIXME: get the error code and throw is at an IOException from Errno Exception // FIXME: get the error code and throw is at an IOException from Errno Exception
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Failed to delete SA with ID: " + mResourceId); Log.e(TAG, "Failed to delete SA with ID: " + mResourceId);
} }
}
getResourceTracker().give(); getResourceTracker().give();
} }
@@ -597,10 +594,8 @@ public class IpSecService extends IIpSecService.Stub {
.append(super.toString()) .append(super.toString())
.append(", mSocket=") .append(", mSocket=")
.append(mSocket) .append(mSocket)
.append(", mSpis[OUT].mResourceId=") .append(", mSpi.mResourceId=")
.append(mSpis[IpSecTransform.DIRECTION_OUT].mResourceId) .append(mSpi.mResourceId)
.append(", mSpis[IN].mResourceId=")
.append(mSpis[IpSecTransform.DIRECTION_IN].mResourceId)
.append(", mConfig=") .append(", mConfig=")
.append(mConfig) .append(mConfig)
.append("}"); .append("}");
@@ -609,23 +604,16 @@ public class IpSecService extends IIpSecService.Stub {
} }
private final class SpiRecord extends KernelResourceRecord { private final class SpiRecord extends KernelResourceRecord {
private final int mDirection; private final String mSourceAddress;
private final String mLocalAddress; private final String mDestinationAddress;
private final String mRemoteAddress;
private int mSpi; private int mSpi;
private boolean mOwnedByTransform = false; private boolean mOwnedByTransform = false;
SpiRecord( SpiRecord(int resourceId, String sourceAddress, String destinationAddress, int spi) {
int resourceId,
int direction,
String localAddress,
String remoteAddress,
int spi) {
super(resourceId); super(resourceId);
mDirection = direction; mSourceAddress = sourceAddress;
mLocalAddress = localAddress; mDestinationAddress = destinationAddress;
mRemoteAddress = remoteAddress;
mSpi = spi; mSpi = spi;
} }
@@ -646,7 +634,7 @@ public class IpSecService extends IIpSecService.Stub {
mSrvConfig mSrvConfig
.getNetdInstance() .getNetdInstance()
.ipSecDeleteSecurityAssociation( .ipSecDeleteSecurityAssociation(
mResourceId, mDirection, mLocalAddress, mRemoteAddress, mSpi); mResourceId, mSourceAddress, mDestinationAddress, mSpi);
} catch (ServiceSpecificException e) { } catch (ServiceSpecificException e) {
// FIXME: get the error code and throw is at an IOException from Errno Exception // FIXME: get the error code and throw is at an IOException from Errno Exception
} catch (RemoteException e) { } catch (RemoteException e) {
@@ -662,6 +650,10 @@ public class IpSecService extends IIpSecService.Stub {
return mSpi; return mSpi;
} }
public String getDestinationAddress() {
return mDestinationAddress;
}
public void setOwnedByTransform() { public void setOwnedByTransform() {
if (mOwnedByTransform) { if (mOwnedByTransform) {
// Programming error // Programming error
@@ -689,12 +681,10 @@ public class IpSecService extends IIpSecService.Stub {
.append(super.toString()) .append(super.toString())
.append(", mSpi=") .append(", mSpi=")
.append(mSpi) .append(mSpi)
.append(", mDirection=") .append(", mSourceAddress=")
.append(mDirection) .append(mSourceAddress)
.append(", mLocalAddress=") .append(", mDestinationAddress=")
.append(mLocalAddress) .append(mDestinationAddress)
.append(", mRemoteAddress=")
.append(mRemoteAddress)
.append(", mOwnedByTransform=") .append(", mOwnedByTransform=")
.append(mOwnedByTransform) .append(mOwnedByTransform)
.append("}"); .append("}");
@@ -772,8 +762,11 @@ public class IpSecService extends IIpSecService.Stub {
/** @hide */ /** @hide */
@VisibleForTesting @VisibleForTesting
public IpSecService(Context context, IpSecServiceConfiguration config) { public IpSecService(Context context, IpSecServiceConfiguration config) {
this(context, config, (fd, uid) -> { this(
try{ context,
config,
(fd, uid) -> {
try {
TrafficStats.setThreadStatsUid(uid); TrafficStats.setThreadStatsUid(uid);
TrafficStats.tagFileDescriptor(fd); TrafficStats.tagFileDescriptor(fd);
} finally { } finally {
@@ -845,8 +838,8 @@ public class IpSecService extends IIpSecService.Stub {
*/ */
private static void checkDirection(int direction) { private static void checkDirection(int direction) {
switch (direction) { switch (direction) {
case IpSecTransform.DIRECTION_OUT: case IpSecManager.DIRECTION_OUT:
case IpSecTransform.DIRECTION_IN: case IpSecManager.DIRECTION_IN:
return; return;
} }
throw new IllegalArgumentException("Invalid Direction: " + direction); throw new IllegalArgumentException("Invalid Direction: " + direction);
@@ -855,10 +848,8 @@ public class IpSecService extends IIpSecService.Stub {
/** Get a new SPI and maintain the reservation in the system server */ /** Get a new SPI and maintain the reservation in the system server */
@Override @Override
public synchronized IpSecSpiResponse allocateSecurityParameterIndex( public synchronized IpSecSpiResponse allocateSecurityParameterIndex(
int direction, String remoteAddress, int requestedSpi, IBinder binder) String destinationAddress, int requestedSpi, IBinder binder) throws RemoteException {
throws RemoteException { checkInetAddress(destinationAddress);
checkDirection(direction);
checkInetAddress(remoteAddress);
/* requestedSpi can be anything in the int range, so no check is needed. */ /* requestedSpi can be anything in the int range, so no check is needed. */
checkNotNull(binder, "Null Binder passed to allocateSecurityParameterIndex"); checkNotNull(binder, "Null Binder passed to allocateSecurityParameterIndex");
@@ -866,28 +857,21 @@ public class IpSecService extends IIpSecService.Stub {
final int resourceId = mNextResourceId++; final int resourceId = mNextResourceId++;
int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
String localAddress = "";
try { try {
if (!userRecord.mSpiQuotaTracker.isAvailable()) { if (!userRecord.mSpiQuotaTracker.isAvailable()) {
return new IpSecSpiResponse( return new IpSecSpiResponse(
IpSecManager.Status.RESOURCE_UNAVAILABLE, INVALID_RESOURCE_ID, spi); IpSecManager.Status.RESOURCE_UNAVAILABLE, INVALID_RESOURCE_ID, spi);
} }
spi = spi =
mSrvConfig mSrvConfig
.getNetdInstance() .getNetdInstance()
.ipSecAllocateSpi( .ipSecAllocateSpi(resourceId, "", destinationAddress, requestedSpi);
resourceId,
direction,
localAddress,
remoteAddress,
requestedSpi);
Log.d(TAG, "Allocated SPI " + spi); Log.d(TAG, "Allocated SPI " + spi);
userRecord.mSpiRecords.put( userRecord.mSpiRecords.put(
resourceId, resourceId,
new RefcountedResource<SpiRecord>( new RefcountedResource<SpiRecord>(
new SpiRecord(resourceId, direction, localAddress, remoteAddress, spi), new SpiRecord(resourceId, "", destinationAddress, spi), binder));
binder));
} catch (ServiceSpecificException e) { } catch (ServiceSpecificException e) {
// TODO: Add appropriate checks when other ServiceSpecificException types are supported // TODO: Add appropriate checks when other ServiceSpecificException types are supported
return new IpSecSpiResponse( return new IpSecSpiResponse(
@@ -1032,10 +1016,10 @@ public class IpSecService extends IIpSecService.Stub {
} }
@VisibleForTesting @VisibleForTesting
void validateAlgorithms(IpSecConfig config, int direction) throws IllegalArgumentException { void validateAlgorithms(IpSecConfig config) throws IllegalArgumentException {
IpSecAlgorithm auth = config.getAuthentication(direction); IpSecAlgorithm auth = config.getAuthentication();
IpSecAlgorithm crypt = config.getEncryption(direction); IpSecAlgorithm crypt = config.getEncryption();
IpSecAlgorithm aead = config.getAuthenticatedEncryption(direction); IpSecAlgorithm aead = config.getAuthenticatedEncryption();
// Validate the algorithm set // Validate the algorithm set
Preconditions.checkArgument( Preconditions.checkArgument(
@@ -1062,29 +1046,6 @@ public class IpSecService extends IIpSecService.Stub {
private void checkIpSecConfig(IpSecConfig config) { private void checkIpSecConfig(IpSecConfig config) {
UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
if (config.getLocalAddress() == null) {
throw new IllegalArgumentException("Invalid null Local InetAddress");
}
if (config.getRemoteAddress() == null) {
throw new IllegalArgumentException("Invalid null Remote InetAddress");
}
switch (config.getMode()) {
case IpSecTransform.MODE_TRANSPORT:
if (!config.getLocalAddress().isEmpty()) {
throw new IllegalArgumentException("Non-empty Local Address");
}
// Must be valid, and not a wildcard
checkInetAddress(config.getRemoteAddress());
break;
case IpSecTransform.MODE_TUNNEL:
break;
default:
throw new IllegalArgumentException(
"Invalid IpSecTransform.mode: " + config.getMode());
}
switch (config.getEncapType()) { switch (config.getEncapType()) {
case IpSecTransform.ENCAP_NONE: case IpSecTransform.ENCAP_NONE:
break; break;
@@ -1103,11 +1064,36 @@ public class IpSecService extends IIpSecService.Stub {
throw new IllegalArgumentException("Invalid Encap Type: " + config.getEncapType()); throw new IllegalArgumentException("Invalid Encap Type: " + config.getEncapType());
} }
for (int direction : DIRECTIONS) { validateAlgorithms(config);
validateAlgorithms(config, direction);
// Retrieve SPI record; will throw IllegalArgumentException if not found // Retrieve SPI record; will throw IllegalArgumentException if not found
userRecord.mSpiRecords.getResourceOrThrow(config.getSpiResourceId(direction)); SpiRecord s = userRecord.mSpiRecords.getResourceOrThrow(config.getSpiResourceId());
// If no remote address is supplied, then use one from the SPI.
if (TextUtils.isEmpty(config.getDestinationAddress())) {
config.setDestinationAddress(s.getDestinationAddress());
}
// All remote addresses must match
if (!config.getDestinationAddress().equals(s.getDestinationAddress())) {
throw new IllegalArgumentException("Mismatched remote addresseses.");
}
// This check is technically redundant due to the chain of custody between the SPI and
// the IpSecConfig, but in the future if the dest is allowed to be set explicitly in
// the transform, this will prevent us from messing up.
checkInetAddress(config.getDestinationAddress());
// Require a valid source address for all transforms.
checkInetAddress(config.getSourceAddress());
switch (config.getMode()) {
case IpSecTransform.MODE_TRANSPORT:
case IpSecTransform.MODE_TUNNEL:
break;
default:
throw new IllegalArgumentException(
"Invalid IpSecTransform.mode: " + config.getMode());
} }
} }
@@ -1127,13 +1113,12 @@ public class IpSecService extends IIpSecService.Stub {
UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
// Avoid resizing by creating a dependency array of min-size 3 (1 UDP encap + 2 SPIs) // Avoid resizing by creating a dependency array of min-size 2 (1 UDP encap + 1 SPI)
List<RefcountedResource> dependencies = new ArrayList<>(3); List<RefcountedResource> dependencies = new ArrayList<>(2);
if (!userRecord.mTransformQuotaTracker.isAvailable()) { if (!userRecord.mTransformQuotaTracker.isAvailable()) {
return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
} }
SpiRecord[] spis = new SpiRecord[DIRECTIONS.length];
int encapType, encapLocalPort = 0, encapRemotePort = 0; int encapType, encapLocalPort = 0, encapRemotePort = 0;
EncapSocketRecord socketRecord = null; EncapSocketRecord socketRecord = null;
@@ -1149,29 +1134,25 @@ public class IpSecService extends IIpSecService.Stub {
encapRemotePort = c.getEncapRemotePort(); encapRemotePort = c.getEncapRemotePort();
} }
for (int direction : DIRECTIONS) { IpSecAlgorithm auth = c.getAuthentication();
IpSecAlgorithm auth = c.getAuthentication(direction); IpSecAlgorithm crypt = c.getEncryption();
IpSecAlgorithm crypt = c.getEncryption(direction); IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption();
IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption(direction);
RefcountedResource<SpiRecord> refcountedSpiRecord = RefcountedResource<SpiRecord> refcountedSpiRecord =
userRecord.mSpiRecords.getRefcountedResourceOrThrow( userRecord.mSpiRecords.getRefcountedResourceOrThrow(c.getSpiResourceId());
c.getSpiResourceId(direction));
dependencies.add(refcountedSpiRecord); dependencies.add(refcountedSpiRecord);
SpiRecord spiRecord = refcountedSpiRecord.getResource();
spis[direction] = refcountedSpiRecord.getResource();
int spi = spis[direction].getSpi();
try { try {
mSrvConfig mSrvConfig
.getNetdInstance() .getNetdInstance()
.ipSecAddSecurityAssociation( .ipSecAddSecurityAssociation(
resourceId, resourceId,
c.getMode(), c.getMode(),
direction, c.getSourceAddress(),
c.getLocalAddress(), c.getDestinationAddress(),
c.getRemoteAddress(), (c.getNetwork() != null) ? c.getNetwork().netId : 0,
(c.getNetwork() != null) ? c.getNetwork().getNetworkHandle() : 0, spiRecord.getSpi(),
spi,
(auth != null) ? auth.getName() : "", (auth != null) ? auth.getName() : "",
(auth != null) ? auth.getKey() : new byte[] {}, (auth != null) ? auth.getKey() : new byte[] {},
(auth != null) ? auth.getTruncationLengthBits() : 0, (auth != null) ? auth.getTruncationLengthBits() : 0,
@@ -1188,12 +1169,11 @@ public class IpSecService extends IIpSecService.Stub {
// FIXME: get the error code and throw is at an IOException from Errno Exception // FIXME: get the error code and throw is at an IOException from Errno Exception
return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
} }
}
// Both SAs were created successfully, time to construct a record and lock it away // Both SAs were created successfully, time to construct a record and lock it away
userRecord.mTransformRecords.put( userRecord.mTransformRecords.put(
resourceId, resourceId,
new RefcountedResource<TransformRecord>( new RefcountedResource<TransformRecord>(
new TransformRecord(resourceId, c, spis, socketRecord), new TransformRecord(resourceId, c, spiRecord, socketRecord),
binder, binder,
dependencies.toArray(new RefcountedResource[dependencies.size()]))); dependencies.toArray(new RefcountedResource[dependencies.size()])));
return new IpSecTransformResponse(IpSecManager.Status.OK, resourceId); return new IpSecTransformResponse(IpSecManager.Status.OK, resourceId);
@@ -1217,9 +1197,9 @@ public class IpSecService extends IIpSecService.Stub {
*/ */
@Override @Override
public synchronized void applyTransportModeTransform( public synchronized void applyTransportModeTransform(
ParcelFileDescriptor socket, int resourceId) throws RemoteException { ParcelFileDescriptor socket, int direction, int resourceId) throws RemoteException {
UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
checkDirection(direction);
// Get transform record; if no transform is found, will throw IllegalArgumentException // Get transform record; if no transform is found, will throw IllegalArgumentException
TransformRecord info = userRecord.mTransformRecords.getResourceOrThrow(resourceId); TransformRecord info = userRecord.mTransformRecords.getResourceOrThrow(resourceId);
@@ -1230,17 +1210,15 @@ public class IpSecService extends IIpSecService.Stub {
IpSecConfig c = info.getConfig(); IpSecConfig c = info.getConfig();
try { try {
for (int direction : DIRECTIONS) {
mSrvConfig mSrvConfig
.getNetdInstance() .getNetdInstance()
.ipSecApplyTransportModeTransform( .ipSecApplyTransportModeTransform(
socket.getFileDescriptor(), socket.getFileDescriptor(),
resourceId, resourceId,
direction, direction,
c.getLocalAddress(), c.getSourceAddress(),
c.getRemoteAddress(), c.getDestinationAddress(),
info.getSpiRecord(direction).getSpi()); info.getSpiRecord().getSpi());
}
} catch (ServiceSpecificException e) { } catch (ServiceSpecificException e) {
if (e.errorCode == EINVAL) { if (e.errorCode == EINVAL) {
throw new IllegalArgumentException(e.toString()); throw new IllegalArgumentException(e.toString());
@@ -1251,14 +1229,14 @@ public class IpSecService extends IIpSecService.Stub {
} }
/** /**
* Remove a transport mode transform from a socket, applying the default (empty) policy. This * Remove transport mode transforms from a socket, applying the default (empty) policy. This
* will ensure that NO IPsec policy is applied to the socket (would be the equivalent of * ensures that NO IPsec policy is applied to the socket (would be the equivalent of applying a
* applying a policy that performs no IPsec). Today the resourceId parameter is passed but not * policy that performs no IPsec). Today the resourceId parameter is passed but not used:
* used: reserved for future improved input validation. * reserved for future improved input validation.
*/ */
@Override @Override
public synchronized void removeTransportModeTransform(ParcelFileDescriptor socket, int resourceId) public synchronized void removeTransportModeTransforms(
throws RemoteException { ParcelFileDescriptor socket, int resourceId) throws RemoteException {
try { try {
mSrvConfig mSrvConfig
.getNetdInstance() .getNetdInstance()

View File

@@ -36,19 +36,16 @@ public class IpSecConfigTest {
public void testDefaults() throws Exception { public void testDefaults() throws Exception {
IpSecConfig c = new IpSecConfig(); IpSecConfig c = new IpSecConfig();
assertEquals(IpSecTransform.MODE_TRANSPORT, c.getMode()); assertEquals(IpSecTransform.MODE_TRANSPORT, c.getMode());
assertEquals("", c.getLocalAddress()); assertEquals("", c.getSourceAddress());
assertEquals("", c.getRemoteAddress()); assertEquals("", c.getDestinationAddress());
assertNull(c.getNetwork()); assertNull(c.getNetwork());
assertEquals(IpSecTransform.ENCAP_NONE, c.getEncapType()); assertEquals(IpSecTransform.ENCAP_NONE, c.getEncapType());
assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getEncapSocketResourceId()); assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getEncapSocketResourceId());
assertEquals(0, c.getEncapRemotePort()); assertEquals(0, c.getEncapRemotePort());
assertEquals(0, c.getNattKeepaliveInterval()); assertEquals(0, c.getNattKeepaliveInterval());
for (int direction : assertNull(c.getEncryption());
new int[] {IpSecTransform.DIRECTION_OUT, IpSecTransform.DIRECTION_IN}) { assertNull(c.getAuthentication());
assertNull(c.getEncryption(direction)); assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getSpiResourceId());
assertNull(c.getAuthentication(direction));
assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getSpiResourceId(direction));
}
} }
@Test @Test
@@ -57,34 +54,21 @@ public class IpSecConfigTest {
IpSecConfig c = new IpSecConfig(); IpSecConfig c = new IpSecConfig();
c.setMode(IpSecTransform.MODE_TUNNEL); c.setMode(IpSecTransform.MODE_TUNNEL);
c.setLocalAddress("0.0.0.0"); c.setSourceAddress("0.0.0.0");
c.setRemoteAddress("1.2.3.4"); c.setDestinationAddress("1.2.3.4");
c.setEncapType(android.system.OsConstants.UDP_ENCAP_ESPINUDP); c.setEncapType(android.system.OsConstants.UDP_ENCAP_ESPINUDP);
c.setEncapSocketResourceId(7); c.setEncapSocketResourceId(7);
c.setEncapRemotePort(22); c.setEncapRemotePort(22);
c.setNattKeepaliveInterval(42); c.setNattKeepaliveInterval(42);
c.setEncryption( c.setEncryption(
IpSecTransform.DIRECTION_OUT,
new IpSecAlgorithm( new IpSecAlgorithm(
IpSecAlgorithm.CRYPT_AES_CBC, IpSecAlgorithm.CRYPT_AES_CBC,
new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF})); new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF}));
c.setAuthentication( c.setAuthentication(
IpSecTransform.DIRECTION_OUT,
new IpSecAlgorithm( new IpSecAlgorithm(
IpSecAlgorithm.AUTH_HMAC_MD5, IpSecAlgorithm.AUTH_HMAC_MD5,
new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0})); new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0}));
c.setSpiResourceId(IpSecTransform.DIRECTION_OUT, 1984); c.setSpiResourceId(1984);
c.setEncryption(
IpSecTransform.DIRECTION_IN,
new IpSecAlgorithm(
IpSecAlgorithm.CRYPT_AES_CBC,
new byte[] {2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF}));
c.setAuthentication(
IpSecTransform.DIRECTION_IN,
new IpSecAlgorithm(
IpSecAlgorithm.AUTH_HMAC_MD5,
new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 1}));
c.setSpiResourceId(IpSecTransform.DIRECTION_IN, 99);
assertParcelingIsLossless(c); assertParcelingIsLossless(c);
} }

View File

@@ -81,15 +81,13 @@ public class IpSecManagerTest {
IpSecSpiResponse spiResp = IpSecSpiResponse spiResp =
new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, DROID_SPI); new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, DROID_SPI);
when(mMockIpSecService.allocateSecurityParameterIndex( when(mMockIpSecService.allocateSecurityParameterIndex(
eq(IpSecTransform.DIRECTION_IN),
eq(GOOGLE_DNS_4.getHostAddress()), eq(GOOGLE_DNS_4.getHostAddress()),
eq(DROID_SPI), eq(DROID_SPI),
anyObject())) anyObject()))
.thenReturn(spiResp); .thenReturn(spiResp);
IpSecManager.SecurityParameterIndex droidSpi = IpSecManager.SecurityParameterIndex droidSpi =
mIpSecManager.allocateSecurityParameterIndex( mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4, DROID_SPI);
IpSecTransform.DIRECTION_IN, GOOGLE_DNS_4, DROID_SPI);
assertEquals(DROID_SPI, droidSpi.getSpi()); assertEquals(DROID_SPI, droidSpi.getSpi());
droidSpi.close(); droidSpi.close();
@@ -103,15 +101,13 @@ public class IpSecManagerTest {
IpSecSpiResponse spiResp = IpSecSpiResponse spiResp =
new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, DROID_SPI); new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, DROID_SPI);
when(mMockIpSecService.allocateSecurityParameterIndex( when(mMockIpSecService.allocateSecurityParameterIndex(
eq(IpSecTransform.DIRECTION_OUT),
eq(GOOGLE_DNS_4.getHostAddress()), eq(GOOGLE_DNS_4.getHostAddress()),
eq(IpSecManager.INVALID_SECURITY_PARAMETER_INDEX), eq(IpSecManager.INVALID_SECURITY_PARAMETER_INDEX),
anyObject())) anyObject()))
.thenReturn(spiResp); .thenReturn(spiResp);
IpSecManager.SecurityParameterIndex randomSpi = IpSecManager.SecurityParameterIndex randomSpi =
mIpSecManager.allocateSecurityParameterIndex( mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4);
IpSecTransform.DIRECTION_OUT, GOOGLE_DNS_4);
assertEquals(DROID_SPI, randomSpi.getSpi()); assertEquals(DROID_SPI, randomSpi.getSpi());
@@ -124,16 +120,15 @@ public class IpSecManagerTest {
* Throws resource unavailable exception * Throws resource unavailable exception
*/ */
@Test @Test
public void testAllocSpiResUnavaiableExeption() throws Exception { public void testAllocSpiResUnavailableException() throws Exception {
IpSecSpiResponse spiResp = IpSecSpiResponse spiResp =
new IpSecSpiResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE, 0, 0); new IpSecSpiResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE, 0, 0);
when(mMockIpSecService.allocateSecurityParameterIndex( when(mMockIpSecService.allocateSecurityParameterIndex(
anyInt(), anyString(), anyInt(), anyObject())) anyString(), anyInt(), anyObject()))
.thenReturn(spiResp); .thenReturn(spiResp);
try { try {
mIpSecManager.allocateSecurityParameterIndex( mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4);
IpSecTransform.DIRECTION_OUT, GOOGLE_DNS_4);
fail("ResourceUnavailableException was not thrown"); fail("ResourceUnavailableException was not thrown");
} catch (IpSecManager.ResourceUnavailableException e) { } catch (IpSecManager.ResourceUnavailableException e) {
} }
@@ -143,15 +138,14 @@ public class IpSecManagerTest {
* Throws spi unavailable exception * Throws spi unavailable exception
*/ */
@Test @Test
public void testAllocSpiSpiUnavaiableExeption() throws Exception { public void testAllocSpiSpiUnavailableException() throws Exception {
IpSecSpiResponse spiResp = new IpSecSpiResponse(IpSecManager.Status.SPI_UNAVAILABLE, 0, 0); IpSecSpiResponse spiResp = new IpSecSpiResponse(IpSecManager.Status.SPI_UNAVAILABLE, 0, 0);
when(mMockIpSecService.allocateSecurityParameterIndex( when(mMockIpSecService.allocateSecurityParameterIndex(
anyInt(), anyString(), anyInt(), anyObject())) anyString(), anyInt(), anyObject()))
.thenReturn(spiResp); .thenReturn(spiResp);
try { try {
mIpSecManager.allocateSecurityParameterIndex( mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4);
IpSecTransform.DIRECTION_OUT, GOOGLE_DNS_4);
fail("ResourceUnavailableException was not thrown"); fail("ResourceUnavailableException was not thrown");
} catch (IpSecManager.ResourceUnavailableException e) { } catch (IpSecManager.ResourceUnavailableException e) {
} }
@@ -163,8 +157,7 @@ public class IpSecManagerTest {
@Test @Test
public void testRequestAllocInvalidSpi() throws Exception { public void testRequestAllocInvalidSpi() throws Exception {
try { try {
mIpSecManager.allocateSecurityParameterIndex( mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4, 0);
IpSecTransform.DIRECTION_OUT, GOOGLE_DNS_4, 0);
fail("Able to allocate invalid spi"); fail("Able to allocate invalid spi");
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
} }

View File

@@ -32,7 +32,6 @@ import android.net.IpSecAlgorithm;
import android.net.IpSecConfig; import android.net.IpSecConfig;
import android.net.IpSecManager; import android.net.IpSecManager;
import android.net.IpSecSpiResponse; import android.net.IpSecSpiResponse;
import android.net.IpSecTransform;
import android.net.IpSecTransformResponse; import android.net.IpSecTransformResponse;
import android.net.NetworkUtils; import android.net.NetworkUtils;
import android.os.Binder; import android.os.Binder;
@@ -54,14 +53,14 @@ import org.junit.runners.Parameterized;
@RunWith(Parameterized.class) @RunWith(Parameterized.class)
public class IpSecServiceParameterizedTest { public class IpSecServiceParameterizedTest {
private static final int TEST_SPI_OUT = 0xD1201D; private static final int TEST_SPI = 0xD1201D;
private static final int TEST_SPI_IN = TEST_SPI_OUT + 1;
private final String mRemoteAddr; private final String mDestinationAddr;
private final String mSourceAddr;
@Parameterized.Parameters @Parameterized.Parameters
public static Collection ipSecConfigs() { public static Collection ipSecConfigs() {
return Arrays.asList(new Object[][] {{"8.8.4.4"}, {"2601::10"}}); return Arrays.asList(new Object[][] {{"1.2.3.4", "8.8.4.4"}, {"2601::2", "2601::10"}});
} }
private static final byte[] AEAD_KEY = { private static final byte[] AEAD_KEY = {
@@ -96,11 +95,9 @@ public class IpSecServiceParameterizedTest {
private static final IpSecAlgorithm AEAD_ALGO = private static final IpSecAlgorithm AEAD_ALGO =
new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
private static final int[] DIRECTIONS = public IpSecServiceParameterizedTest(String sourceAddr, String destAddr) {
new int[] {IpSecTransform.DIRECTION_IN, IpSecTransform.DIRECTION_OUT}; mSourceAddr = sourceAddr;
mDestinationAddr = destAddr;
public IpSecServiceParameterizedTest(String remoteAddr) {
mRemoteAddr = remoteAddr;
} }
@Before @Before
@@ -116,44 +113,30 @@ public class IpSecServiceParameterizedTest {
@Test @Test
public void testIpSecServiceReserveSpi() throws Exception { public void testIpSecServiceReserveSpi() throws Exception {
when(mMockNetd.ipSecAllocateSpi( when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
anyInt(), .thenReturn(TEST_SPI);
eq(IpSecTransform.DIRECTION_OUT),
anyString(),
eq(mRemoteAddr),
eq(TEST_SPI_OUT)))
.thenReturn(TEST_SPI_OUT);
IpSecSpiResponse spiResp = IpSecSpiResponse spiResp =
mIpSecService.allocateSecurityParameterIndex( mIpSecService.allocateSecurityParameterIndex(
IpSecTransform.DIRECTION_OUT, mRemoteAddr, TEST_SPI_OUT, new Binder()); mDestinationAddr, TEST_SPI, new Binder());
assertEquals(IpSecManager.Status.OK, spiResp.status); assertEquals(IpSecManager.Status.OK, spiResp.status);
assertEquals(TEST_SPI_OUT, spiResp.spi); assertEquals(TEST_SPI, spiResp.spi);
} }
@Test @Test
public void testReleaseSecurityParameterIndex() throws Exception { public void testReleaseSecurityParameterIndex() throws Exception {
when(mMockNetd.ipSecAllocateSpi( when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
anyInt(), .thenReturn(TEST_SPI);
eq(IpSecTransform.DIRECTION_OUT),
anyString(),
eq(mRemoteAddr),
eq(TEST_SPI_OUT)))
.thenReturn(TEST_SPI_OUT);
IpSecSpiResponse spiResp = IpSecSpiResponse spiResp =
mIpSecService.allocateSecurityParameterIndex( mIpSecService.allocateSecurityParameterIndex(
IpSecTransform.DIRECTION_OUT, mRemoteAddr, TEST_SPI_OUT, new Binder()); mDestinationAddr, TEST_SPI, new Binder());
mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId); mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
verify(mMockNetd) verify(mMockNetd)
.ipSecDeleteSecurityAssociation( .ipSecDeleteSecurityAssociation(
eq(spiResp.resourceId), eq(spiResp.resourceId), anyString(), anyString(), eq(TEST_SPI));
anyInt(),
anyString(),
anyString(),
eq(TEST_SPI_OUT));
// Verify quota and RefcountedResource objects cleaned up // Verify quota and RefcountedResource objects cleaned up
IpSecService.UserRecord userRecord = IpSecService.UserRecord userRecord =
@@ -169,17 +152,12 @@ public class IpSecServiceParameterizedTest {
@Test @Test
public void testSecurityParameterIndexBinderDeath() throws Exception { public void testSecurityParameterIndexBinderDeath() throws Exception {
when(mMockNetd.ipSecAllocateSpi( when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
anyInt(), .thenReturn(TEST_SPI);
eq(IpSecTransform.DIRECTION_OUT),
anyString(),
eq(mRemoteAddr),
eq(TEST_SPI_OUT)))
.thenReturn(TEST_SPI_OUT);
IpSecSpiResponse spiResp = IpSecSpiResponse spiResp =
mIpSecService.allocateSecurityParameterIndex( mIpSecService.allocateSecurityParameterIndex(
IpSecTransform.DIRECTION_OUT, mRemoteAddr, TEST_SPI_OUT, new Binder()); mDestinationAddr, TEST_SPI, new Binder());
IpSecService.UserRecord userRecord = IpSecService.UserRecord userRecord =
mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid()); mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
@@ -190,11 +168,7 @@ public class IpSecServiceParameterizedTest {
verify(mMockNetd) verify(mMockNetd)
.ipSecDeleteSecurityAssociation( .ipSecDeleteSecurityAssociation(
eq(spiResp.resourceId), eq(spiResp.resourceId), anyString(), anyString(), eq(TEST_SPI));
anyInt(),
anyString(),
anyString(),
eq(TEST_SPI_OUT));
// Verify quota and RefcountedResource objects cleaned up // Verify quota and RefcountedResource objects cleaned up
assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent); assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
@@ -206,14 +180,12 @@ public class IpSecServiceParameterizedTest {
} }
} }
private int getNewSpiResourceId(int direction, String remoteAddress, int returnSpi) private int getNewSpiResourceId(String remoteAddress, int returnSpi) throws Exception {
throws Exception { when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), anyString(), anyInt()))
when(mMockNetd.ipSecAllocateSpi(anyInt(), anyInt(), anyString(), anyString(), anyInt()))
.thenReturn(returnSpi); .thenReturn(returnSpi);
IpSecSpiResponse spi = IpSecSpiResponse spi =
mIpSecService.allocateSecurityParameterIndex( mIpSecService.allocateSecurityParameterIndex(
direction,
NetworkUtils.numericToInetAddress(remoteAddress).getHostAddress(), NetworkUtils.numericToInetAddress(remoteAddress).getHostAddress(),
IpSecManager.INVALID_SECURITY_PARAMETER_INDEX, IpSecManager.INVALID_SECURITY_PARAMETER_INDEX,
new Binder()); new Binder());
@@ -221,20 +193,14 @@ public class IpSecServiceParameterizedTest {
} }
private void addDefaultSpisAndRemoteAddrToIpSecConfig(IpSecConfig config) throws Exception { private void addDefaultSpisAndRemoteAddrToIpSecConfig(IpSecConfig config) throws Exception {
config.setSpiResourceId( config.setSpiResourceId(getNewSpiResourceId(mDestinationAddr, TEST_SPI));
IpSecTransform.DIRECTION_OUT, config.setSourceAddress(mSourceAddr);
getNewSpiResourceId(IpSecTransform.DIRECTION_OUT, mRemoteAddr, TEST_SPI_OUT)); config.setDestinationAddress(mDestinationAddr);
config.setSpiResourceId(
IpSecTransform.DIRECTION_IN,
getNewSpiResourceId(IpSecTransform.DIRECTION_IN, mRemoteAddr, TEST_SPI_IN));
config.setRemoteAddress(mRemoteAddr);
} }
private void addAuthAndCryptToIpSecConfig(IpSecConfig config) throws Exception { private void addAuthAndCryptToIpSecConfig(IpSecConfig config) throws Exception {
for (int direction : DIRECTIONS) { config.setEncryption(CRYPT_ALGO);
config.setEncryption(direction, CRYPT_ALGO); config.setAuthentication(AUTH_ALGO);
config.setAuthentication(direction, AUTH_ALGO);
}
} }
@Test @Test
@@ -251,32 +217,10 @@ public class IpSecServiceParameterizedTest {
.ipSecAddSecurityAssociation( .ipSecAddSecurityAssociation(
eq(createTransformResp.resourceId), eq(createTransformResp.resourceId),
anyInt(), anyInt(),
eq(IpSecTransform.DIRECTION_OUT),
anyString(), anyString(),
anyString(), anyString(),
anyLong(), anyLong(),
eq(TEST_SPI_OUT), eq(TEST_SPI),
eq(IpSecAlgorithm.AUTH_HMAC_SHA256),
eq(AUTH_KEY),
anyInt(),
eq(IpSecAlgorithm.CRYPT_AES_CBC),
eq(CRYPT_KEY),
anyInt(),
eq(""),
eq(new byte[] {}),
eq(0),
anyInt(),
anyInt(),
anyInt());
verify(mMockNetd)
.ipSecAddSecurityAssociation(
eq(createTransformResp.resourceId),
anyInt(),
eq(IpSecTransform.DIRECTION_IN),
anyString(),
anyString(),
anyLong(),
eq(TEST_SPI_IN),
eq(IpSecAlgorithm.AUTH_HMAC_SHA256), eq(IpSecAlgorithm.AUTH_HMAC_SHA256),
eq(AUTH_KEY), eq(AUTH_KEY),
anyInt(), anyInt(),
@@ -296,8 +240,7 @@ public class IpSecServiceParameterizedTest {
IpSecConfig ipSecConfig = new IpSecConfig(); IpSecConfig ipSecConfig = new IpSecConfig();
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig); addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
ipSecConfig.setAuthenticatedEncryption(IpSecTransform.DIRECTION_OUT, AEAD_ALGO); ipSecConfig.setAuthenticatedEncryption(AEAD_ALGO);
ipSecConfig.setAuthenticatedEncryption(IpSecTransform.DIRECTION_IN, AEAD_ALGO);
IpSecTransformResponse createTransformResp = IpSecTransformResponse createTransformResp =
mIpSecService.createTransportModeTransform(ipSecConfig, new Binder()); mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
@@ -307,32 +250,10 @@ public class IpSecServiceParameterizedTest {
.ipSecAddSecurityAssociation( .ipSecAddSecurityAssociation(
eq(createTransformResp.resourceId), eq(createTransformResp.resourceId),
anyInt(), anyInt(),
eq(IpSecTransform.DIRECTION_OUT),
anyString(), anyString(),
anyString(), anyString(),
anyLong(), anyLong(),
eq(TEST_SPI_OUT), eq(TEST_SPI),
eq(""),
eq(new byte[] {}),
eq(0),
eq(""),
eq(new byte[] {}),
eq(0),
eq(IpSecAlgorithm.AUTH_CRYPT_AES_GCM),
eq(AEAD_KEY),
anyInt(),
anyInt(),
anyInt(),
anyInt());
verify(mMockNetd)
.ipSecAddSecurityAssociation(
eq(createTransformResp.resourceId),
anyInt(),
eq(IpSecTransform.DIRECTION_IN),
anyString(),
anyString(),
anyLong(),
eq(TEST_SPI_IN),
eq(""), eq(""),
eq(new byte[] {}), eq(new byte[] {}),
eq(0), eq(0),
@@ -359,18 +280,7 @@ public class IpSecServiceParameterizedTest {
verify(mMockNetd) verify(mMockNetd)
.ipSecDeleteSecurityAssociation( .ipSecDeleteSecurityAssociation(
eq(createTransformResp.resourceId), eq(createTransformResp.resourceId), anyString(), anyString(), eq(TEST_SPI));
eq(IpSecTransform.DIRECTION_OUT),
anyString(),
anyString(),
eq(TEST_SPI_OUT));
verify(mMockNetd)
.ipSecDeleteSecurityAssociation(
eq(createTransformResp.resourceId),
eq(IpSecTransform.DIRECTION_IN),
anyString(),
anyString(),
eq(TEST_SPI_IN));
// Verify quota and RefcountedResource objects cleaned up // Verify quota and RefcountedResource objects cleaned up
IpSecService.UserRecord userRecord = IpSecService.UserRecord userRecord =
@@ -404,18 +314,7 @@ public class IpSecServiceParameterizedTest {
verify(mMockNetd) verify(mMockNetd)
.ipSecDeleteSecurityAssociation( .ipSecDeleteSecurityAssociation(
eq(createTransformResp.resourceId), eq(createTransformResp.resourceId), anyString(), anyString(), eq(TEST_SPI));
eq(IpSecTransform.DIRECTION_OUT),
anyString(),
anyString(),
eq(TEST_SPI_OUT));
verify(mMockNetd)
.ipSecDeleteSecurityAssociation(
eq(createTransformResp.resourceId),
eq(IpSecTransform.DIRECTION_IN),
anyString(),
anyString(),
eq(TEST_SPI_IN));
// Verify quota and RefcountedResource objects cleaned up // Verify quota and RefcountedResource objects cleaned up
assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent); assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
@@ -439,30 +338,22 @@ public class IpSecServiceParameterizedTest {
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket()); ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
int resourceId = createTransformResp.resourceId; int resourceId = createTransformResp.resourceId;
mIpSecService.applyTransportModeTransform(pfd, resourceId); mIpSecService.applyTransportModeTransform(pfd, IpSecManager.DIRECTION_OUT, resourceId);
verify(mMockNetd) verify(mMockNetd)
.ipSecApplyTransportModeTransform( .ipSecApplyTransportModeTransform(
eq(pfd.getFileDescriptor()), eq(pfd.getFileDescriptor()),
eq(resourceId), eq(resourceId),
eq(IpSecTransform.DIRECTION_OUT), eq(IpSecManager.DIRECTION_OUT),
anyString(), anyString(),
anyString(), anyString(),
eq(TEST_SPI_OUT)); eq(TEST_SPI));
verify(mMockNetd)
.ipSecApplyTransportModeTransform(
eq(pfd.getFileDescriptor()),
eq(resourceId),
eq(IpSecTransform.DIRECTION_IN),
anyString(),
anyString(),
eq(TEST_SPI_IN));
} }
@Test @Test
public void testRemoveTransportModeTransform() throws Exception { public void testRemoveTransportModeTransform() throws Exception {
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket()); ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
mIpSecService.removeTransportModeTransform(pfd, 1); mIpSecService.removeTransportModeTransforms(pfd, 1);
verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd.getFileDescriptor()); verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd.getFileDescriptor());
} }

View File

@@ -105,9 +105,6 @@ public class IpSecServiceTest {
private static final IpSecAlgorithm AEAD_ALGO = private static final IpSecAlgorithm AEAD_ALGO =
new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
private static final int[] DIRECTIONS =
new int[] {IpSecTransform.DIRECTION_IN, IpSecTransform.DIRECTION_OUT};
static { static {
try { try {
INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0}); INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0});
@@ -303,83 +300,75 @@ public class IpSecServiceTest {
@Test @Test
public void testValidateAlgorithmsAuth() { public void testValidateAlgorithmsAuth() {
for (int direction : DIRECTIONS) {
// Validate that correct algorithm type succeeds // Validate that correct algorithm type succeeds
IpSecConfig config = new IpSecConfig(); IpSecConfig config = new IpSecConfig();
config.setAuthentication(direction, AUTH_ALGO); config.setAuthentication(AUTH_ALGO);
mIpSecService.validateAlgorithms(config, direction); mIpSecService.validateAlgorithms(config);
// Validate that incorrect algorithm types fails // Validate that incorrect algorithm types fails
for (IpSecAlgorithm algo : new IpSecAlgorithm[] {CRYPT_ALGO, AEAD_ALGO}) { for (IpSecAlgorithm algo : new IpSecAlgorithm[] {CRYPT_ALGO, AEAD_ALGO}) {
try { try {
config = new IpSecConfig(); config = new IpSecConfig();
config.setAuthentication(direction, algo); config.setAuthentication(algo);
mIpSecService.validateAlgorithms(config, direction); mIpSecService.validateAlgorithms(config);
fail("Did not throw exception on invalid algorithm type"); fail("Did not throw exception on invalid algorithm type");
} catch (IllegalArgumentException expected) { } catch (IllegalArgumentException expected) {
} }
} }
} }
}
@Test @Test
public void testValidateAlgorithmsCrypt() { public void testValidateAlgorithmsCrypt() {
for (int direction : DIRECTIONS) {
// Validate that correct algorithm type succeeds // Validate that correct algorithm type succeeds
IpSecConfig config = new IpSecConfig(); IpSecConfig config = new IpSecConfig();
config.setEncryption(direction, CRYPT_ALGO); config.setEncryption(CRYPT_ALGO);
mIpSecService.validateAlgorithms(config, direction); mIpSecService.validateAlgorithms(config);
// Validate that incorrect algorithm types fails // Validate that incorrect algorithm types fails
for (IpSecAlgorithm algo : new IpSecAlgorithm[] {AUTH_ALGO, AEAD_ALGO}) { for (IpSecAlgorithm algo : new IpSecAlgorithm[] {AUTH_ALGO, AEAD_ALGO}) {
try { try {
config = new IpSecConfig(); config = new IpSecConfig();
config.setEncryption(direction, algo); config.setEncryption(algo);
mIpSecService.validateAlgorithms(config, direction); mIpSecService.validateAlgorithms(config);
fail("Did not throw exception on invalid algorithm type"); fail("Did not throw exception on invalid algorithm type");
} catch (IllegalArgumentException expected) { } catch (IllegalArgumentException expected) {
} }
} }
} }
}
@Test @Test
public void testValidateAlgorithmsAead() { public void testValidateAlgorithmsAead() {
for (int direction : DIRECTIONS) {
// Validate that correct algorithm type succeeds // Validate that correct algorithm type succeeds
IpSecConfig config = new IpSecConfig(); IpSecConfig config = new IpSecConfig();
config.setAuthenticatedEncryption(direction, AEAD_ALGO); config.setAuthenticatedEncryption(AEAD_ALGO);
mIpSecService.validateAlgorithms(config, direction); mIpSecService.validateAlgorithms(config);
// Validate that incorrect algorithm types fails // Validate that incorrect algorithm types fails
for (IpSecAlgorithm algo : new IpSecAlgorithm[] {AUTH_ALGO, CRYPT_ALGO}) { for (IpSecAlgorithm algo : new IpSecAlgorithm[] {AUTH_ALGO, CRYPT_ALGO}) {
try { try {
config = new IpSecConfig(); config = new IpSecConfig();
config.setAuthenticatedEncryption(direction, algo); config.setAuthenticatedEncryption(algo);
mIpSecService.validateAlgorithms(config, direction); mIpSecService.validateAlgorithms(config);
fail("Did not throw exception on invalid algorithm type"); fail("Did not throw exception on invalid algorithm type");
} catch (IllegalArgumentException expected) { } catch (IllegalArgumentException expected) {
} }
} }
} }
}
@Test @Test
public void testValidateAlgorithmsAuthCrypt() { public void testValidateAlgorithmsAuthCrypt() {
for (int direction : DIRECTIONS) {
// Validate that correct algorithm type succeeds // Validate that correct algorithm type succeeds
IpSecConfig config = new IpSecConfig(); IpSecConfig config = new IpSecConfig();
config.setAuthentication(direction, AUTH_ALGO); config.setAuthentication(AUTH_ALGO);
config.setEncryption(direction, CRYPT_ALGO); config.setEncryption(CRYPT_ALGO);
mIpSecService.validateAlgorithms(config, direction); mIpSecService.validateAlgorithms(config);
}
} }
@Test @Test
public void testValidateAlgorithmsNoAlgorithms() { public void testValidateAlgorithmsNoAlgorithms() {
IpSecConfig config = new IpSecConfig(); IpSecConfig config = new IpSecConfig();
try { try {
mIpSecService.validateAlgorithms(config, IpSecTransform.DIRECTION_IN); mIpSecService.validateAlgorithms(config);
fail("Expected exception; no algorithms specified"); fail("Expected exception; no algorithms specified");
} catch (IllegalArgumentException expected) { } catch (IllegalArgumentException expected) {
} }
@@ -388,10 +377,10 @@ public class IpSecServiceTest {
@Test @Test
public void testValidateAlgorithmsAeadWithAuth() { public void testValidateAlgorithmsAeadWithAuth() {
IpSecConfig config = new IpSecConfig(); IpSecConfig config = new IpSecConfig();
config.setAuthenticatedEncryption(IpSecTransform.DIRECTION_IN, AEAD_ALGO); config.setAuthenticatedEncryption(AEAD_ALGO);
config.setAuthentication(IpSecTransform.DIRECTION_IN, AUTH_ALGO); config.setAuthentication(AUTH_ALGO);
try { try {
mIpSecService.validateAlgorithms(config, IpSecTransform.DIRECTION_IN); mIpSecService.validateAlgorithms(config);
fail("Expected exception; both AEAD and auth algorithm specified"); fail("Expected exception; both AEAD and auth algorithm specified");
} catch (IllegalArgumentException expected) { } catch (IllegalArgumentException expected) {
} }
@@ -400,10 +389,10 @@ public class IpSecServiceTest {
@Test @Test
public void testValidateAlgorithmsAeadWithCrypt() { public void testValidateAlgorithmsAeadWithCrypt() {
IpSecConfig config = new IpSecConfig(); IpSecConfig config = new IpSecConfig();
config.setAuthenticatedEncryption(IpSecTransform.DIRECTION_IN, AEAD_ALGO); config.setAuthenticatedEncryption(AEAD_ALGO);
config.setEncryption(IpSecTransform.DIRECTION_IN, CRYPT_ALGO); config.setEncryption(CRYPT_ALGO);
try { try {
mIpSecService.validateAlgorithms(config, IpSecTransform.DIRECTION_IN); mIpSecService.validateAlgorithms(config);
fail("Expected exception; both AEAD and crypt algorithm specified"); fail("Expected exception; both AEAD and crypt algorithm specified");
} catch (IllegalArgumentException expected) { } catch (IllegalArgumentException expected) {
} }
@@ -412,11 +401,11 @@ public class IpSecServiceTest {
@Test @Test
public void testValidateAlgorithmsAeadWithAuthAndCrypt() { public void testValidateAlgorithmsAeadWithAuthAndCrypt() {
IpSecConfig config = new IpSecConfig(); IpSecConfig config = new IpSecConfig();
config.setAuthenticatedEncryption(IpSecTransform.DIRECTION_IN, AEAD_ALGO); config.setAuthenticatedEncryption(AEAD_ALGO);
config.setAuthentication(IpSecTransform.DIRECTION_IN, AUTH_ALGO); config.setAuthentication(AUTH_ALGO);
config.setEncryption(IpSecTransform.DIRECTION_IN, CRYPT_ALGO); config.setEncryption(CRYPT_ALGO);
try { try {
mIpSecService.validateAlgorithms(config, IpSecTransform.DIRECTION_IN); mIpSecService.validateAlgorithms(config);
fail("Expected exception; AEAD, auth and crypt algorithm specified"); fail("Expected exception; AEAD, auth and crypt algorithm specified");
} catch (IllegalArgumentException expected) { } catch (IllegalArgumentException expected) {
} }
@@ -434,7 +423,7 @@ public class IpSecServiceTest {
@Test @Test
public void testRemoveTransportModeTransform() throws Exception { public void testRemoveTransportModeTransform() throws Exception {
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket()); ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
mIpSecService.removeTransportModeTransform(pfd, 1); mIpSecService.removeTransportModeTransforms(pfd, 1);
verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd.getFileDescriptor()); verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd.getFileDescriptor());
} }
@@ -447,7 +436,7 @@ public class IpSecServiceTest {
try { try {
IpSecSpiResponse spiResp = IpSecSpiResponse spiResp =
mIpSecService.allocateSecurityParameterIndex( mIpSecService.allocateSecurityParameterIndex(
IpSecTransform.DIRECTION_OUT, address, DROID_SPI, new Binder()); address, DROID_SPI, new Binder());
fail("Invalid address was passed through IpSecService validation: " + address); fail("Invalid address was passed through IpSecService validation: " + address);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
} catch (Exception e) { } catch (Exception e) {
@@ -519,7 +508,6 @@ public class IpSecServiceTest {
// tracks the resource ID. // tracks the resource ID.
when(mMockNetd.ipSecAllocateSpi( when(mMockNetd.ipSecAllocateSpi(
anyInt(), anyInt(),
eq(IpSecTransform.DIRECTION_OUT),
anyString(), anyString(),
eq(InetAddress.getLoopbackAddress().getHostAddress()), eq(InetAddress.getLoopbackAddress().getHostAddress()),
anyInt())) anyInt()))
@@ -528,7 +516,6 @@ public class IpSecServiceTest {
for (int i = 0; i < MAX_NUM_SPIS; i++) { for (int i = 0; i < MAX_NUM_SPIS; i++) {
IpSecSpiResponse newSpi = IpSecSpiResponse newSpi =
mIpSecService.allocateSecurityParameterIndex( mIpSecService.allocateSecurityParameterIndex(
0x1,
InetAddress.getLoopbackAddress().getHostAddress(), InetAddress.getLoopbackAddress().getHostAddress(),
DROID_SPI + i, DROID_SPI + i,
new Binder()); new Binder());
@@ -544,7 +531,6 @@ public class IpSecServiceTest {
// Try to reserve one more SPI, and should fail. // Try to reserve one more SPI, and should fail.
IpSecSpiResponse extraSpi = IpSecSpiResponse extraSpi =
mIpSecService.allocateSecurityParameterIndex( mIpSecService.allocateSecurityParameterIndex(
0x1,
InetAddress.getLoopbackAddress().getHostAddress(), InetAddress.getLoopbackAddress().getHostAddress(),
DROID_SPI + MAX_NUM_SPIS, DROID_SPI + MAX_NUM_SPIS,
new Binder()); new Binder());
@@ -558,7 +544,6 @@ public class IpSecServiceTest {
// Should successfully reserve one more spi. // Should successfully reserve one more spi.
extraSpi = extraSpi =
mIpSecService.allocateSecurityParameterIndex( mIpSecService.allocateSecurityParameterIndex(
0x1,
InetAddress.getLoopbackAddress().getHostAddress(), InetAddress.getLoopbackAddress().getHostAddress(),
DROID_SPI + MAX_NUM_SPIS, DROID_SPI + MAX_NUM_SPIS,
new Binder()); new Binder());