Merge changes from topic "ipsec-svc-cleanup" am: 9778c7884f
am: ae61e0c6e8
Change-Id: If8803e2fc98adb2f08a5bf2944fc60d0f0e71acd
This commit is contained in:
@@ -24,6 +24,7 @@ import com.android.internal.util.HexDump;
|
|||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IpSecAlgorithm specifies a single algorithm that can be applied to an IpSec Transform. Refer to
|
* IpSecAlgorithm specifies a single algorithm that can be applied to an IpSec Transform. Refer to
|
||||||
@@ -75,13 +76,7 @@ public final class IpSecAlgorithm implements Parcelable {
|
|||||||
public static final String AUTH_HMAC_SHA512 = "hmac(sha512)";
|
public static final String AUTH_HMAC_SHA512 = "hmac(sha512)";
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
@StringDef({
|
@StringDef({CRYPT_AES_CBC, AUTH_HMAC_MD5, AUTH_HMAC_SHA1, AUTH_HMAC_SHA256, AUTH_HMAC_SHA512})
|
||||||
CRYPT_AES_CBC,
|
|
||||||
AUTH_HMAC_MD5,
|
|
||||||
AUTH_HMAC_SHA1,
|
|
||||||
AUTH_HMAC_SHA256,
|
|
||||||
AUTH_HMAC_SHA512
|
|
||||||
})
|
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public @interface AlgorithmName {}
|
public @interface AlgorithmName {}
|
||||||
|
|
||||||
@@ -197,4 +192,12 @@ public final class IpSecAlgorithm implements Parcelable {
|
|||||||
.append("}")
|
.append("}")
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** package */
|
||||||
|
static boolean equals(IpSecAlgorithm lhs, IpSecAlgorithm rhs) {
|
||||||
|
if (lhs == null || rhs == null) return (lhs == rhs);
|
||||||
|
return (lhs.mName.equals(rhs.mName)
|
||||||
|
&& Arrays.equals(lhs.mKey, rhs.mKey)
|
||||||
|
&& lhs.mTruncLenBits == rhs.mTruncLenBits);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,105 +17,170 @@ package android.net;
|
|||||||
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.util.Log;
|
|
||||||
import java.net.InetAddress;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import java.net.UnknownHostException;
|
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
public final class IpSecConfig implements Parcelable {
|
public final class IpSecConfig implements Parcelable {
|
||||||
private static final String TAG = "IpSecConfig";
|
private static final String TAG = "IpSecConfig";
|
||||||
|
|
||||||
//MODE_TRANSPORT or MODE_TUNNEL
|
// MODE_TRANSPORT or MODE_TUNNEL
|
||||||
int mode;
|
private int mMode = IpSecTransform.MODE_TRANSPORT;
|
||||||
|
|
||||||
// For tunnel mode
|
// Needs to be valid only for tunnel mode
|
||||||
InetAddress localAddress;
|
// Preventing this from being null simplifies Java->Native binder
|
||||||
|
private String mLocalAddress = "";
|
||||||
|
|
||||||
InetAddress remoteAddress;
|
// Preventing this from being null simplifies Java->Native binder
|
||||||
|
private String mRemoteAddress = "";
|
||||||
|
|
||||||
// Limit selection by network interface
|
// The underlying network interface that represents the "gateway" Network
|
||||||
Network network;
|
// for outbound packets. It may also be used to select packets.
|
||||||
|
private Network mNetwork;
|
||||||
|
|
||||||
public static class Flow {
|
public static class Flow {
|
||||||
// Minimum requirements for identifying a transform
|
// Minimum requirements for identifying a transform
|
||||||
// SPI identifying the IPsec flow in packet processing
|
// SPI identifying the IPsec flow in packet processing
|
||||||
// and a remote IP address
|
// and a remote IP address
|
||||||
int spiResourceId;
|
private int mSpiResourceId = IpSecManager.INVALID_RESOURCE_ID;
|
||||||
|
|
||||||
// Encryption Algorithm
|
// Encryption Algorithm
|
||||||
IpSecAlgorithm encryption;
|
private IpSecAlgorithm mEncryption;
|
||||||
|
|
||||||
// Authentication Algorithm
|
// Authentication Algorithm
|
||||||
IpSecAlgorithm authentication;
|
private IpSecAlgorithm mAuthentication;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return new StringBuilder()
|
return new StringBuilder()
|
||||||
.append("{spiResourceId=")
|
.append("{mSpiResourceId=")
|
||||||
.append(spiResourceId)
|
.append(mSpiResourceId)
|
||||||
.append(", encryption=")
|
.append(", mEncryption=")
|
||||||
.append(encryption)
|
.append(mEncryption)
|
||||||
.append(", authentication=")
|
.append(", mAuthentication=")
|
||||||
.append(authentication)
|
.append(mAuthentication)
|
||||||
.append("}")
|
.append("}")
|
||||||
.toString();
|
.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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final Flow[] flow = new Flow[] {new Flow(), new Flow()};
|
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
|
||||||
int encapType;
|
private int mEncapType = IpSecTransform.ENCAP_NONE;
|
||||||
int encapLocalPortResourceId;
|
private int mEncapSocketResourceId = IpSecManager.INVALID_RESOURCE_ID;
|
||||||
int encapRemotePort;
|
private int mEncapRemotePort;
|
||||||
|
|
||||||
// An interval, in seconds between the NattKeepalive packets
|
// An interval, in seconds between the NattKeepalive packets
|
||||||
int nattKeepaliveInterval;
|
private int mNattKeepaliveInterval;
|
||||||
|
|
||||||
|
/** Set the mode for this IPsec transform */
|
||||||
|
public void setMode(int mode) {
|
||||||
|
mMode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set the local IP address for Tunnel mode */
|
||||||
|
public void setLocalAddress(String localAddress) {
|
||||||
|
if (localAddress == null) {
|
||||||
|
throw new IllegalArgumentException("localAddress may not be null!");
|
||||||
|
}
|
||||||
|
mLocalAddress = localAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set the remote IP address for this IPsec transform */
|
||||||
|
public void setRemoteAddress(String remoteAddress) {
|
||||||
|
if (remoteAddress == null) {
|
||||||
|
throw new IllegalArgumentException("remoteAddress may not be null!");
|
||||||
|
}
|
||||||
|
mRemoteAddress = remoteAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set the SPI for a given direction by resource ID */
|
||||||
|
public void setSpiResourceId(int direction, int resourceId) {
|
||||||
|
mFlow[direction].mSpiResourceId = resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set the encryption algorithm for a given direction */
|
||||||
|
public void setEncryption(int direction, IpSecAlgorithm encryption) {
|
||||||
|
mFlow[direction].mEncryption = encryption;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set the authentication algorithm for a given direction */
|
||||||
|
public void setAuthentication(int direction, IpSecAlgorithm authentication) {
|
||||||
|
mFlow[direction].mAuthentication = authentication;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNetwork(Network network) {
|
||||||
|
mNetwork = network;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEncapType(int encapType) {
|
||||||
|
mEncapType = encapType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEncapSocketResourceId(int resourceId) {
|
||||||
|
mEncapSocketResourceId = resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEncapRemotePort(int port) {
|
||||||
|
mEncapRemotePort = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNattKeepaliveInterval(int interval) {
|
||||||
|
mNattKeepaliveInterval = interval;
|
||||||
|
}
|
||||||
|
|
||||||
// Transport or Tunnel
|
// Transport or Tunnel
|
||||||
public int getMode() {
|
public int getMode() {
|
||||||
return mode;
|
return mMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InetAddress getLocalAddress() {
|
public String getLocalAddress() {
|
||||||
return localAddress;
|
return mLocalAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSpiResourceId(int direction) {
|
public int getSpiResourceId(int direction) {
|
||||||
return flow[direction].spiResourceId;
|
return mFlow[direction].mSpiResourceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InetAddress getRemoteAddress() {
|
public String getRemoteAddress() {
|
||||||
return remoteAddress;
|
return mRemoteAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IpSecAlgorithm getEncryption(int direction) {
|
public IpSecAlgorithm getEncryption(int direction) {
|
||||||
return flow[direction].encryption;
|
return mFlow[direction].mEncryption;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IpSecAlgorithm getAuthentication(int direction) {
|
public IpSecAlgorithm getAuthentication(int direction) {
|
||||||
return flow[direction].authentication;
|
return mFlow[direction].mAuthentication;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Network getNetwork() {
|
public Network getNetwork() {
|
||||||
return network;
|
return mNetwork;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getEncapType() {
|
public int getEncapType() {
|
||||||
return encapType;
|
return mEncapType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getEncapLocalResourceId() {
|
public int getEncapSocketResourceId() {
|
||||||
return encapLocalPortResourceId;
|
return mEncapSocketResourceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getEncapRemotePort() {
|
public int getEncapRemotePort() {
|
||||||
return encapRemotePort;
|
return mEncapRemotePort;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNattKeepaliveInterval() {
|
public int getNattKeepaliveInterval() {
|
||||||
return nattKeepaliveInterval;
|
return mNattKeepaliveInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parcelable Methods
|
// Parcelable Methods
|
||||||
@@ -127,82 +192,70 @@ public final class IpSecConfig implements Parcelable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeToParcel(Parcel out, int flags) {
|
public void writeToParcel(Parcel out, int flags) {
|
||||||
// TODO: Use a byte array or other better method for storing IPs that can also include scope
|
out.writeInt(mMode);
|
||||||
out.writeString((localAddress != null) ? localAddress.getHostAddress() : null);
|
out.writeString(mLocalAddress);
|
||||||
// TODO: Use a byte array or other better method for storing IPs that can also include scope
|
out.writeString(mRemoteAddress);
|
||||||
out.writeString((remoteAddress != null) ? remoteAddress.getHostAddress() : null);
|
out.writeParcelable(mNetwork, flags);
|
||||||
out.writeParcelable(network, flags);
|
out.writeInt(mFlow[IpSecTransform.DIRECTION_IN].mSpiResourceId);
|
||||||
out.writeInt(flow[IpSecTransform.DIRECTION_IN].spiResourceId);
|
out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mEncryption, flags);
|
||||||
out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryption, flags);
|
out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mAuthentication, flags);
|
||||||
out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authentication, flags);
|
out.writeInt(mFlow[IpSecTransform.DIRECTION_OUT].mSpiResourceId);
|
||||||
out.writeInt(flow[IpSecTransform.DIRECTION_OUT].spiResourceId);
|
out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mEncryption, flags);
|
||||||
out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryption, flags);
|
out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mAuthentication, flags);
|
||||||
out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authentication, flags);
|
out.writeInt(mEncapType);
|
||||||
out.writeInt(encapType);
|
out.writeInt(mEncapSocketResourceId);
|
||||||
out.writeInt(encapLocalPortResourceId);
|
out.writeInt(mEncapRemotePort);
|
||||||
out.writeInt(encapRemotePort);
|
out.writeInt(mNattKeepaliveInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Package Private: Used by the IpSecTransform.Builder;
|
@VisibleForTesting
|
||||||
// there should be no public constructor for this object
|
public IpSecConfig() {}
|
||||||
IpSecConfig() {}
|
|
||||||
|
|
||||||
private static InetAddress readInetAddressFromParcel(Parcel in) {
|
|
||||||
String addrString = in.readString();
|
|
||||||
if (addrString == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return InetAddress.getByName(addrString);
|
|
||||||
} catch (UnknownHostException e) {
|
|
||||||
Log.wtf(TAG, "Invalid IpAddress " + addrString);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IpSecConfig(Parcel in) {
|
private IpSecConfig(Parcel in) {
|
||||||
localAddress = readInetAddressFromParcel(in);
|
mMode = in.readInt();
|
||||||
remoteAddress = readInetAddressFromParcel(in);
|
mLocalAddress = in.readString();
|
||||||
network = (Network) in.readParcelable(Network.class.getClassLoader());
|
mRemoteAddress = in.readString();
|
||||||
flow[IpSecTransform.DIRECTION_IN].spiResourceId = in.readInt();
|
mNetwork = (Network) in.readParcelable(Network.class.getClassLoader());
|
||||||
flow[IpSecTransform.DIRECTION_IN].encryption =
|
mFlow[IpSecTransform.DIRECTION_IN].mSpiResourceId = in.readInt();
|
||||||
|
mFlow[IpSecTransform.DIRECTION_IN].mEncryption =
|
||||||
(IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
|
(IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
|
||||||
flow[IpSecTransform.DIRECTION_IN].authentication =
|
mFlow[IpSecTransform.DIRECTION_IN].mAuthentication =
|
||||||
(IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
|
(IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
|
||||||
flow[IpSecTransform.DIRECTION_OUT].spiResourceId = in.readInt();
|
mFlow[IpSecTransform.DIRECTION_OUT].mSpiResourceId = in.readInt();
|
||||||
flow[IpSecTransform.DIRECTION_OUT].encryption =
|
mFlow[IpSecTransform.DIRECTION_OUT].mEncryption =
|
||||||
(IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
|
(IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
|
||||||
flow[IpSecTransform.DIRECTION_OUT].authentication =
|
mFlow[IpSecTransform.DIRECTION_OUT].mAuthentication =
|
||||||
(IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
|
(IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
|
||||||
encapType = in.readInt();
|
mEncapType = in.readInt();
|
||||||
encapLocalPortResourceId = in.readInt();
|
mEncapSocketResourceId = in.readInt();
|
||||||
encapRemotePort = in.readInt();
|
mEncapRemotePort = in.readInt();
|
||||||
|
mNattKeepaliveInterval = in.readInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder strBuilder = new StringBuilder();
|
StringBuilder strBuilder = new StringBuilder();
|
||||||
strBuilder
|
strBuilder
|
||||||
.append("{mode=")
|
.append("{mMode=")
|
||||||
.append(mode == IpSecTransform.MODE_TUNNEL ? "TUNNEL" : "TRANSPORT")
|
.append(mMode == IpSecTransform.MODE_TUNNEL ? "TUNNEL" : "TRANSPORT")
|
||||||
.append(", localAddress=")
|
.append(", mLocalAddress=")
|
||||||
.append(localAddress)
|
.append(mLocalAddress)
|
||||||
.append(", remoteAddress=")
|
.append(", mRemoteAddress=")
|
||||||
.append(remoteAddress)
|
.append(mRemoteAddress)
|
||||||
.append(", network=")
|
.append(", mNetwork=")
|
||||||
.append(network)
|
.append(mNetwork)
|
||||||
.append(", encapType=")
|
.append(", mEncapType=")
|
||||||
.append(encapType)
|
.append(mEncapType)
|
||||||
.append(", encapLocalPortResourceId=")
|
.append(", mEncapSocketResourceId=")
|
||||||
.append(encapLocalPortResourceId)
|
.append(mEncapSocketResourceId)
|
||||||
.append(", encapRemotePort=")
|
.append(", mEncapRemotePort=")
|
||||||
.append(encapRemotePort)
|
.append(mEncapRemotePort)
|
||||||
.append(", nattKeepaliveInterval=")
|
.append(", mNattKeepaliveInterval=")
|
||||||
.append(nattKeepaliveInterval)
|
.append(mNattKeepaliveInterval)
|
||||||
.append(", flow[OUT]=")
|
.append(", mFlow[OUT]=")
|
||||||
.append(flow[IpSecTransform.DIRECTION_OUT])
|
.append(mFlow[IpSecTransform.DIRECTION_OUT])
|
||||||
.append(", flow[IN]=")
|
.append(", mFlow[IN]=")
|
||||||
.append(flow[IpSecTransform.DIRECTION_IN])
|
.append(mFlow[IpSecTransform.DIRECTION_IN])
|
||||||
.append("}");
|
.append("}");
|
||||||
|
|
||||||
return strBuilder.toString();
|
return strBuilder.toString();
|
||||||
@@ -218,4 +271,22 @@ public final class IpSecConfig implements Parcelable {
|
|||||||
return new IpSecConfig[size];
|
return new IpSecConfig[size];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public static boolean equals(IpSecConfig lhs, IpSecConfig rhs) {
|
||||||
|
if (lhs == null || rhs == null) return (lhs == rhs);
|
||||||
|
return (lhs.mMode == rhs.mMode
|
||||||
|
&& lhs.mLocalAddress.equals(rhs.mLocalAddress)
|
||||||
|
&& lhs.mRemoteAddress.equals(rhs.mRemoteAddress)
|
||||||
|
&& ((lhs.mNetwork != null && lhs.mNetwork.equals(rhs.mNetwork))
|
||||||
|
|| (lhs.mNetwork == rhs.mNetwork))
|
||||||
|
&& lhs.mEncapType == rhs.mEncapType
|
||||||
|
&& lhs.mEncapSocketResourceId == rhs.mEncapSocketResourceId
|
||||||
|
&& lhs.mEncapRemotePort == rhs.mEncapRemotePort
|
||||||
|
&& lhs.mNattKeepaliveInterval == rhs.mNattKeepaliveInterval
|
||||||
|
&& IpSecConfig.Flow.equals(lhs.mFlow[IpSecTransform.DIRECTION_OUT],
|
||||||
|
rhs.mFlow[IpSecTransform.DIRECTION_OUT])
|
||||||
|
&& IpSecConfig.Flow.equals(lhs.mFlow[IpSecTransform.DIRECTION_IN],
|
||||||
|
rhs.mFlow[IpSecTransform.DIRECTION_IN]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ import android.os.RemoteException;
|
|||||||
import android.util.AndroidException;
|
import android.util.AndroidException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
import dalvik.system.CloseGuard;
|
import dalvik.system.CloseGuard;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
@@ -188,7 +190,8 @@ public final class IpSecManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
int getResourceId() {
|
@VisibleForTesting
|
||||||
|
public int getResourceId() {
|
||||||
return mResourceId;
|
return mResourceId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -489,7 +492,8 @@ public final class IpSecManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
int getResourceId() {
|
@VisibleForTesting
|
||||||
|
public int getResourceId() {
|
||||||
return mResourceId;
|
return mResourceId;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -68,10 +68,10 @@ public final class IpSecTransform implements AutoCloseable {
|
|||||||
public @interface TransformDirection {}
|
public @interface TransformDirection {}
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
public static final int MODE_TUNNEL = 0;
|
public static final int MODE_TRANSPORT = 0;
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
public static final int MODE_TRANSPORT = 1;
|
public static final int MODE_TUNNEL = 1;
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
public static final int ENCAP_NONE = 0;
|
public static final int ENCAP_NONE = 0;
|
||||||
@@ -113,7 +113,11 @@ public final class IpSecTransform implements AutoCloseable {
|
|||||||
return IIpSecService.Stub.asInterface(b);
|
return IIpSecService.Stub.asInterface(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkResultStatusAndThrow(int status)
|
/**
|
||||||
|
* Checks the result status and throws an appropriate exception if
|
||||||
|
* the status is not Status.OK.
|
||||||
|
*/
|
||||||
|
private void checkResultStatus(int status)
|
||||||
throws IOException, IpSecManager.ResourceUnavailableException,
|
throws IOException, IpSecManager.ResourceUnavailableException,
|
||||||
IpSecManager.SpiUnavailableException {
|
IpSecManager.SpiUnavailableException {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@@ -141,7 +145,7 @@ public final class IpSecTransform implements AutoCloseable {
|
|||||||
IpSecTransformResponse result =
|
IpSecTransformResponse result =
|
||||||
svc.createTransportModeTransform(mConfig, new Binder());
|
svc.createTransportModeTransform(mConfig, new Binder());
|
||||||
int status = result.status;
|
int status = result.status;
|
||||||
checkResultStatusAndThrow(status);
|
checkResultStatus(status);
|
||||||
mResourceId = result.resourceId;
|
mResourceId = result.resourceId;
|
||||||
|
|
||||||
/* Keepalive will silently fail if not needed by the config; but, if needed and
|
/* Keepalive will silently fail if not needed by the config; but, if needed and
|
||||||
@@ -243,61 +247,20 @@ public final class IpSecTransform implements AutoCloseable {
|
|||||||
|
|
||||||
/* Package */
|
/* Package */
|
||||||
void startKeepalive(Context c) {
|
void startKeepalive(Context c) {
|
||||||
// FIXME: NO_KEEPALIVE needs to be a constant
|
if (mConfig.getNattKeepaliveInterval() != 0) {
|
||||||
if (mConfig.getNattKeepaliveInterval() == 0) {
|
Log.wtf(TAG, "Keepalive not yet supported.");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConnectivityManager cm =
|
|
||||||
(ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
||||||
|
|
||||||
if (mKeepalive != null) {
|
|
||||||
Log.wtf(TAG, "Keepalive already started for this IpSecTransform.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (mKeepaliveSyncLock) {
|
|
||||||
mKeepalive =
|
|
||||||
cm.startNattKeepalive(
|
|
||||||
mConfig.getNetwork(),
|
|
||||||
mConfig.getNattKeepaliveInterval(),
|
|
||||||
mKeepaliveCallback,
|
|
||||||
mConfig.getLocalAddress(),
|
|
||||||
0x1234, /* FIXME: get the real port number again,
|
|
||||||
which we need to retrieve from the provided
|
|
||||||
EncapsulationSocket, and which isn't currently
|
|
||||||
stashed in IpSecConfig */
|
|
||||||
mConfig.getRemoteAddress());
|
|
||||||
try {
|
|
||||||
// FIXME: this is still a horrible way to fudge the synchronous callback
|
|
||||||
mKeepaliveSyncLock.wait(2000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mKeepaliveStatus != ConnectivityManager.PacketKeepalive.SUCCESS) {
|
|
||||||
throw new UnsupportedOperationException("Packet Keepalive cannot be started");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Package */
|
/** @hide */
|
||||||
int getResourceId() {
|
@VisibleForTesting
|
||||||
|
public int getResourceId() {
|
||||||
return mResourceId;
|
return mResourceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Package */
|
/* Package */
|
||||||
void stopKeepalive() {
|
void stopKeepalive() {
|
||||||
if (mKeepalive == null) {
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
mKeepalive.stop();
|
|
||||||
synchronized (mKeepaliveSyncLock) {
|
|
||||||
if (mKeepaliveStatus == ConnectivityManager.PacketKeepalive.SUCCESS) {
|
|
||||||
try {
|
|
||||||
mKeepaliveSyncLock.wait(2000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -323,7 +286,7 @@ public final class IpSecTransform implements AutoCloseable {
|
|||||||
*/
|
*/
|
||||||
public IpSecTransform.Builder setEncryption(
|
public IpSecTransform.Builder setEncryption(
|
||||||
@TransformDirection int direction, IpSecAlgorithm algo) {
|
@TransformDirection int direction, IpSecAlgorithm algo) {
|
||||||
mConfig.flow[direction].encryption = algo;
|
mConfig.setEncryption(direction, algo);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,7 +301,7 @@ public final class IpSecTransform implements AutoCloseable {
|
|||||||
*/
|
*/
|
||||||
public IpSecTransform.Builder setAuthentication(
|
public IpSecTransform.Builder setAuthentication(
|
||||||
@TransformDirection int direction, IpSecAlgorithm algo) {
|
@TransformDirection int direction, IpSecAlgorithm algo) {
|
||||||
mConfig.flow[direction].authentication = algo;
|
mConfig.setAuthentication(direction, algo);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,9 +324,7 @@ public final class IpSecTransform implements AutoCloseable {
|
|||||||
*/
|
*/
|
||||||
public IpSecTransform.Builder setSpi(
|
public IpSecTransform.Builder setSpi(
|
||||||
@TransformDirection int direction, IpSecManager.SecurityParameterIndex spi) {
|
@TransformDirection int direction, IpSecManager.SecurityParameterIndex spi) {
|
||||||
// TODO: convert to using the resource Id of the SPI. Then build() can validate
|
mConfig.setSpiResourceId(direction, spi.getResourceId());
|
||||||
// the owner in the IpSecService
|
|
||||||
mConfig.flow[direction].spiResourceId = spi.getResourceId();
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,7 +339,7 @@ public final class IpSecTransform implements AutoCloseable {
|
|||||||
*/
|
*/
|
||||||
@SystemApi
|
@SystemApi
|
||||||
public IpSecTransform.Builder setUnderlyingNetwork(Network net) {
|
public IpSecTransform.Builder setUnderlyingNetwork(Network net) {
|
||||||
mConfig.network = net;
|
mConfig.setNetwork(net);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,10 +356,9 @@ public final class IpSecTransform implements AutoCloseable {
|
|||||||
*/
|
*/
|
||||||
public IpSecTransform.Builder setIpv4Encapsulation(
|
public IpSecTransform.Builder setIpv4Encapsulation(
|
||||||
IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) {
|
IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) {
|
||||||
// TODO: check encap type is valid.
|
mConfig.setEncapType(ENCAP_ESPINUDP);
|
||||||
mConfig.encapType = ENCAP_ESPINUDP;
|
mConfig.setEncapSocketResourceId(localSocket.getResourceId());
|
||||||
mConfig.encapLocalPortResourceId = localSocket.getResourceId();
|
mConfig.setEncapRemotePort(remotePort);
|
||||||
mConfig.encapRemotePort = remotePort;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,7 +376,7 @@ public final class IpSecTransform implements AutoCloseable {
|
|||||||
*/
|
*/
|
||||||
@SystemApi
|
@SystemApi
|
||||||
public IpSecTransform.Builder setNattKeepalive(int intervalSeconds) {
|
public IpSecTransform.Builder setNattKeepalive(int intervalSeconds) {
|
||||||
mConfig.nattKeepaliveInterval = intervalSeconds;
|
mConfig.setNattKeepaliveInterval(intervalSeconds);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,8 +411,8 @@ public final class IpSecTransform implements AutoCloseable {
|
|||||||
IpSecManager.SpiUnavailableException, IOException {
|
IpSecManager.SpiUnavailableException, IOException {
|
||||||
//FIXME: argument validation here
|
//FIXME: argument validation here
|
||||||
//throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation");
|
//throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation");
|
||||||
mConfig.mode = MODE_TRANSPORT;
|
mConfig.setMode(MODE_TRANSPORT);
|
||||||
mConfig.remoteAddress = remoteAddress;
|
mConfig.setRemoteAddress(remoteAddress.getHostAddress());
|
||||||
return new IpSecTransform(mContext, mConfig).activate();
|
return new IpSecTransform(mContext, mConfig).activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,9 +433,9 @@ public final class IpSecTransform implements AutoCloseable {
|
|||||||
InetAddress localAddress, InetAddress remoteAddress) {
|
InetAddress localAddress, InetAddress remoteAddress) {
|
||||||
//FIXME: argument validation here
|
//FIXME: argument validation here
|
||||||
//throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation");
|
//throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation");
|
||||||
mConfig.localAddress = localAddress;
|
mConfig.setLocalAddress(localAddress.getHostAddress());
|
||||||
mConfig.remoteAddress = remoteAddress;
|
mConfig.setRemoteAddress(remoteAddress.getHostAddress());
|
||||||
mConfig.mode = MODE_TUNNEL;
|
mConfig.setMode(MODE_TUNNEL);
|
||||||
return new IpSecTransform(mContext, mConfig);
|
return new IpSecTransform(mContext, mConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,14 +449,5 @@ public final class IpSecTransform implements AutoCloseable {
|
|||||||
mContext = context;
|
mContext = context;
|
||||||
mConfig = new IpSecConfig();
|
mConfig = new IpSecConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return an {@link IpSecConfig} object for testing purposes.
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
public IpSecConfig getIpSecConfig() {
|
|
||||||
return mConfig;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import android.net.IpSecSpiResponse;
|
|||||||
import android.net.IpSecTransform;
|
import android.net.IpSecTransform;
|
||||||
import android.net.IpSecTransformResponse;
|
import android.net.IpSecTransformResponse;
|
||||||
import android.net.IpSecUdpEncapResponse;
|
import android.net.IpSecUdpEncapResponse;
|
||||||
|
import android.net.NetworkUtils;
|
||||||
import android.net.util.NetdService;
|
import android.net.util.NetdService;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
@@ -42,11 +43,14 @@ import android.os.ServiceSpecificException;
|
|||||||
import android.system.ErrnoException;
|
import android.system.ErrnoException;
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
import android.system.OsConstants;
|
import android.system.OsConstants;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
|
|
||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
@@ -54,6 +58,7 @@ import java.net.InetAddress;
|
|||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import libcore.io.IoUtils;
|
import libcore.io.IoUtils;
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
@@ -252,7 +257,11 @@ public class IpSecService extends IIpSecService.Stub {
|
|||||||
return (mReferenceCount.get() > 0);
|
return (mReferenceCount.get() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkOwnerOrSystemAndThrow() {
|
/**
|
||||||
|
* Ensures that the caller is either the owner of this resource or has the system UID and
|
||||||
|
* throws a SecurityException otherwise.
|
||||||
|
*/
|
||||||
|
public void checkOwnerOrSystem() {
|
||||||
if (uid != Binder.getCallingUid()
|
if (uid != Binder.getCallingUid()
|
||||||
&& android.os.Process.SYSTEM_UID != Binder.getCallingUid()) {
|
&& android.os.Process.SYSTEM_UID != Binder.getCallingUid()) {
|
||||||
throw new SecurityException("Only the owner may access managed resources!");
|
throw new SecurityException("Only the owner may access managed resources!");
|
||||||
@@ -340,7 +349,7 @@ public class IpSecService extends IIpSecService.Stub {
|
|||||||
// The value should never be null unless the resource doesn't exist
|
// The value should never be null unless the resource doesn't exist
|
||||||
// (since we do not allow null resources to be added).
|
// (since we do not allow null resources to be added).
|
||||||
if (val != null) {
|
if (val != null) {
|
||||||
val.checkOwnerOrSystemAndThrow();
|
val.checkOwnerOrSystem();
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@@ -405,12 +414,8 @@ public class IpSecService extends IIpSecService.Stub {
|
|||||||
.ipSecDeleteSecurityAssociation(
|
.ipSecDeleteSecurityAssociation(
|
||||||
mResourceId,
|
mResourceId,
|
||||||
direction,
|
direction,
|
||||||
(mConfig.getLocalAddress() != null)
|
mConfig.getLocalAddress(),
|
||||||
? mConfig.getLocalAddress().getHostAddress()
|
mConfig.getRemoteAddress(),
|
||||||
: "",
|
|
||||||
(mConfig.getRemoteAddress() != null)
|
|
||||||
? mConfig.getRemoteAddress().getHostAddress()
|
|
||||||
: "",
|
|
||||||
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
|
||||||
@@ -638,11 +643,45 @@ public class IpSecService extends IIpSecService.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that the provided InetAddress is valid for use in an IPsec SA. The address must not be
|
||||||
|
* a wildcard address and must be in a numeric form such as 1.2.3.4 or 2001::1.
|
||||||
|
*/
|
||||||
|
private static void checkInetAddress(String inetAddress) {
|
||||||
|
if (TextUtils.isEmpty(inetAddress)) {
|
||||||
|
throw new IllegalArgumentException("Unspecified address");
|
||||||
|
}
|
||||||
|
|
||||||
|
InetAddress checkAddr = NetworkUtils.numericToInetAddress(inetAddress);
|
||||||
|
|
||||||
|
if (checkAddr.isAnyLocalAddress()) {
|
||||||
|
throw new IllegalArgumentException("Inappropriate wildcard address: " + inetAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the user-provided direction field and throws an IllegalArgumentException if it is not
|
||||||
|
* DIRECTION_IN or DIRECTION_OUT
|
||||||
|
*/
|
||||||
|
private static void checkDirection(int direction) {
|
||||||
|
switch (direction) {
|
||||||
|
case IpSecTransform.DIRECTION_OUT:
|
||||||
|
case IpSecTransform.DIRECTION_IN:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Invalid Direction: " + direction);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
/** Get a new SPI and maintain the reservation in the system server */
|
/** Get a new SPI and maintain the reservation in the system server */
|
||||||
public synchronized IpSecSpiResponse reserveSecurityParameterIndex(
|
public synchronized IpSecSpiResponse reserveSecurityParameterIndex(
|
||||||
int direction, String remoteAddress, int requestedSpi, IBinder binder)
|
int direction, String remoteAddress, int requestedSpi, IBinder binder)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
|
checkDirection(direction);
|
||||||
|
checkInetAddress(remoteAddress);
|
||||||
|
/* requestedSpi can be anything in the int range, so no check is needed. */
|
||||||
|
checkNotNull(binder, "Null Binder passed to reserveSecurityParameterIndex");
|
||||||
|
|
||||||
int resourceId = mNextResourceId.getAndIncrement();
|
int resourceId = mNextResourceId.getAndIncrement();
|
||||||
|
|
||||||
int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
|
int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
|
||||||
@@ -651,9 +690,7 @@ public class IpSecService extends IIpSecService.Stub {
|
|||||||
try {
|
try {
|
||||||
if (!mUserQuotaTracker.getUserRecord(Binder.getCallingUid()).spi.isAvailable()) {
|
if (!mUserQuotaTracker.getUserRecord(Binder.getCallingUid()).spi.isAvailable()) {
|
||||||
return new IpSecSpiResponse(
|
return new IpSecSpiResponse(
|
||||||
IpSecManager.Status.RESOURCE_UNAVAILABLE,
|
IpSecManager.Status.RESOURCE_UNAVAILABLE, INVALID_RESOURCE_ID, spi);
|
||||||
INVALID_RESOURCE_ID,
|
|
||||||
spi);
|
|
||||||
}
|
}
|
||||||
spi =
|
spi =
|
||||||
mSrvConfig
|
mSrvConfig
|
||||||
@@ -751,6 +788,8 @@ public class IpSecService extends IIpSecService.Stub {
|
|||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Specified port number must be a valid non-reserved UDP port");
|
"Specified port number must be a valid non-reserved UDP port");
|
||||||
}
|
}
|
||||||
|
checkNotNull(binder, "Null Binder passed to openUdpEncapsulationSocket");
|
||||||
|
|
||||||
int resourceId = mNextResourceId.getAndIncrement();
|
int resourceId = mNextResourceId.getAndIncrement();
|
||||||
FileDescriptor sockFd = null;
|
FileDescriptor sockFd = null;
|
||||||
try {
|
try {
|
||||||
@@ -791,6 +830,67 @@ public class IpSecService extends IIpSecService.Stub {
|
|||||||
releaseManagedResource(mUdpSocketRecords, resourceId, "UdpEncapsulationSocket");
|
releaseManagedResource(mUdpSocketRecords, resourceId, "UdpEncapsulationSocket");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks an IpSecConfig parcel to ensure that the contents are sane and throws an
|
||||||
|
* IllegalArgumentException if they are not.
|
||||||
|
*/
|
||||||
|
private void checkIpSecConfig(IpSecConfig config) {
|
||||||
|
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()) {
|
||||||
|
case IpSecTransform.ENCAP_NONE:
|
||||||
|
break;
|
||||||
|
case IpSecTransform.ENCAP_ESPINUDP:
|
||||||
|
case IpSecTransform.ENCAP_ESPINUDP_NON_IKE:
|
||||||
|
if (mUdpSocketRecords.get(config.getEncapSocketResourceId()) == null) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"No Encapsulation socket for Resource Id: "
|
||||||
|
+ config.getEncapSocketResourceId());
|
||||||
|
}
|
||||||
|
|
||||||
|
int port = config.getEncapRemotePort();
|
||||||
|
if (port <= 0 || port > 0xFFFF) {
|
||||||
|
throw new IllegalArgumentException("Invalid remote UDP port: " + port);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Invalid Encap Type: " + config.getEncapType());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int direction : DIRECTIONS) {
|
||||||
|
IpSecAlgorithm crypt = config.getEncryption(direction);
|
||||||
|
IpSecAlgorithm auth = config.getAuthentication(direction);
|
||||||
|
if (crypt == null && auth == null) {
|
||||||
|
throw new IllegalArgumentException("Encryption and Authentication are both null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mSpiRecords.get(config.getSpiResourceId(direction)) == null) {
|
||||||
|
throw new IllegalStateException("No SPI for specified Resource Id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a transport mode transform, which represent two security associations (one in each
|
* Create a transport mode transform, which represent two security associations (one in each
|
||||||
* direction) in the kernel. The transform will be cached by the system server and must be freed
|
* direction) in the kernel. The transform will be cached by the system server and must be freed
|
||||||
@@ -801,17 +901,19 @@ public class IpSecService extends IIpSecService.Stub {
|
|||||||
@Override
|
@Override
|
||||||
public synchronized IpSecTransformResponse createTransportModeTransform(
|
public synchronized IpSecTransformResponse createTransportModeTransform(
|
||||||
IpSecConfig c, IBinder binder) throws RemoteException {
|
IpSecConfig c, IBinder binder) throws RemoteException {
|
||||||
|
checkIpSecConfig(c);
|
||||||
|
checkNotNull(binder, "Null Binder passed to createTransportModeTransform");
|
||||||
int resourceId = mNextResourceId.getAndIncrement();
|
int resourceId = mNextResourceId.getAndIncrement();
|
||||||
if (!mUserQuotaTracker.getUserRecord(Binder.getCallingUid()).transform.isAvailable()) {
|
if (!mUserQuotaTracker.getUserRecord(Binder.getCallingUid()).transform.isAvailable()) {
|
||||||
return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
|
return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
|
||||||
}
|
}
|
||||||
SpiRecord[] spis = new SpiRecord[DIRECTIONS.length];
|
SpiRecord[] spis = new SpiRecord[DIRECTIONS.length];
|
||||||
// TODO: Basic input validation here since it's coming over the Binder
|
|
||||||
int encapType, encapLocalPort = 0, encapRemotePort = 0;
|
int encapType, encapLocalPort = 0, encapRemotePort = 0;
|
||||||
UdpSocketRecord socketRecord = null;
|
UdpSocketRecord socketRecord = null;
|
||||||
encapType = c.getEncapType();
|
encapType = c.getEncapType();
|
||||||
if (encapType != IpSecTransform.ENCAP_NONE) {
|
if (encapType != IpSecTransform.ENCAP_NONE) {
|
||||||
socketRecord = mUdpSocketRecords.get(c.getEncapLocalResourceId());
|
socketRecord = mUdpSocketRecords.get(c.getEncapSocketResourceId());
|
||||||
encapLocalPort = socketRecord.getPort();
|
encapLocalPort = socketRecord.getPort();
|
||||||
encapRemotePort = c.getEncapRemotePort();
|
encapRemotePort = c.getEncapRemotePort();
|
||||||
}
|
}
|
||||||
@@ -823,20 +925,15 @@ public class IpSecService extends IIpSecService.Stub {
|
|||||||
spis[direction] = mSpiRecords.get(c.getSpiResourceId(direction));
|
spis[direction] = mSpiRecords.get(c.getSpiResourceId(direction));
|
||||||
int spi = spis[direction].getSpi();
|
int spi = spis[direction].getSpi();
|
||||||
try {
|
try {
|
||||||
mSrvConfig.getNetdInstance()
|
mSrvConfig
|
||||||
|
.getNetdInstance()
|
||||||
.ipSecAddSecurityAssociation(
|
.ipSecAddSecurityAssociation(
|
||||||
resourceId,
|
resourceId,
|
||||||
c.getMode(),
|
c.getMode(),
|
||||||
direction,
|
direction,
|
||||||
(c.getLocalAddress() != null)
|
c.getLocalAddress(),
|
||||||
? c.getLocalAddress().getHostAddress()
|
c.getRemoteAddress(),
|
||||||
: "",
|
(c.getNetwork() != null) ? c.getNetwork().getNetworkHandle() : 0,
|
||||||
(c.getRemoteAddress() != null)
|
|
||||||
? c.getRemoteAddress().getHostAddress()
|
|
||||||
: "",
|
|
||||||
(c.getNetwork() != null)
|
|
||||||
? c.getNetwork().getNetworkHandle()
|
|
||||||
: 0,
|
|
||||||
spi,
|
spi,
|
||||||
(auth != null) ? auth.getName() : "",
|
(auth != null) ? auth.getName() : "",
|
||||||
(auth != null) ? auth.getKey() : null,
|
(auth != null) ? auth.getKey() : null,
|
||||||
@@ -899,12 +996,8 @@ public class IpSecService extends IIpSecService.Stub {
|
|||||||
socket.getFileDescriptor(),
|
socket.getFileDescriptor(),
|
||||||
resourceId,
|
resourceId,
|
||||||
direction,
|
direction,
|
||||||
(c.getLocalAddress() != null)
|
c.getLocalAddress(),
|
||||||
? c.getLocalAddress().getHostAddress()
|
c.getRemoteAddress(),
|
||||||
: "",
|
|
||||||
(c.getRemoteAddress() != null)
|
|
||||||
? c.getRemoteAddress().getHostAddress()
|
|
||||||
: "",
|
|
||||||
info.getSpiRecord(direction).getSpi());
|
info.getSpiRecord(direction).getSpi());
|
||||||
}
|
}
|
||||||
} catch (ServiceSpecificException e) {
|
} catch (ServiceSpecificException e) {
|
||||||
|
|||||||
98
tests/net/java/android/net/IpSecConfigTest.java
Normal file
98
tests/net/java/android/net/IpSecConfigTest.java
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package android.net;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.support.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.JUnit4;
|
||||||
|
|
||||||
|
/** Unit tests for {@link IpSecConfig}. */
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(JUnit4.class)
|
||||||
|
public class IpSecConfigTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDefaults() throws Exception {
|
||||||
|
IpSecConfig c = new IpSecConfig();
|
||||||
|
assertEquals(IpSecTransform.MODE_TRANSPORT, c.getMode());
|
||||||
|
assertEquals("", c.getLocalAddress());
|
||||||
|
assertEquals("", c.getRemoteAddress());
|
||||||
|
assertNull(c.getNetwork());
|
||||||
|
assertEquals(IpSecTransform.ENCAP_NONE, c.getEncapType());
|
||||||
|
assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getEncapSocketResourceId());
|
||||||
|
assertEquals(0, c.getEncapRemotePort());
|
||||||
|
assertEquals(0, c.getNattKeepaliveInterval());
|
||||||
|
for (int direction :
|
||||||
|
new int[] {IpSecTransform.DIRECTION_OUT, IpSecTransform.DIRECTION_IN}) {
|
||||||
|
assertNull(c.getEncryption(direction));
|
||||||
|
assertNull(c.getAuthentication(direction));
|
||||||
|
assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getSpiResourceId(direction));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParcelUnparcel() throws Exception {
|
||||||
|
assertParcelingIsLossless(new IpSecConfig());
|
||||||
|
|
||||||
|
IpSecConfig c = new IpSecConfig();
|
||||||
|
c.setMode(IpSecTransform.MODE_TUNNEL);
|
||||||
|
c.setLocalAddress("0.0.0.0");
|
||||||
|
c.setRemoteAddress("1.2.3.4");
|
||||||
|
c.setEncapType(android.system.OsConstants.UDP_ENCAP_ESPINUDP);
|
||||||
|
c.setEncapSocketResourceId(7);
|
||||||
|
c.setEncapRemotePort(22);
|
||||||
|
c.setNattKeepaliveInterval(42);
|
||||||
|
c.setEncryption(
|
||||||
|
IpSecTransform.DIRECTION_OUT,
|
||||||
|
new IpSecAlgorithm(
|
||||||
|
IpSecAlgorithm.CRYPT_AES_CBC,
|
||||||
|
new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF}));
|
||||||
|
c.setAuthentication(
|
||||||
|
IpSecTransform.DIRECTION_OUT,
|
||||||
|
new IpSecAlgorithm(
|
||||||
|
IpSecAlgorithm.AUTH_HMAC_SHA1,
|
||||||
|
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.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_SHA1,
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertParcelingIsLossless(IpSecConfig ci) throws Exception {
|
||||||
|
Parcel p = Parcel.obtain();
|
||||||
|
ci.writeToParcel(p, 0);
|
||||||
|
p.setDataPosition(0);
|
||||||
|
IpSecConfig co = IpSecConfig.CREATOR.createFromParcel(p);
|
||||||
|
assertTrue(IpSecConfig.equals(co, ci));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,276 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.server;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.Matchers.anyInt;
|
||||||
|
import static org.mockito.Matchers.anyLong;
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.INetd;
|
||||||
|
import android.net.IpSecAlgorithm;
|
||||||
|
import android.net.IpSecConfig;
|
||||||
|
import android.net.IpSecManager;
|
||||||
|
import android.net.IpSecSpiResponse;
|
||||||
|
import android.net.IpSecTransform;
|
||||||
|
import android.net.IpSecTransformResponse;
|
||||||
|
import android.net.NetworkUtils;
|
||||||
|
import android.os.Binder;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
|
import android.support.test.filters.SmallTest;
|
||||||
|
import android.system.OsConstants;
|
||||||
|
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.Parameterized;
|
||||||
|
|
||||||
|
/** Unit tests for {@link IpSecService}. */
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(Parameterized.class)
|
||||||
|
public class IpSecServiceParameterizedTest {
|
||||||
|
|
||||||
|
private static final int DROID_SPI = 0xD1201D;
|
||||||
|
private static final int DROID_SPI2 = DROID_SPI + 1;
|
||||||
|
|
||||||
|
private final String mRemoteAddr;
|
||||||
|
|
||||||
|
@Parameterized.Parameters
|
||||||
|
public static Collection ipSecConfigs() {
|
||||||
|
return Arrays.asList(new Object[][] {{"8.8.4.4"}, {"2601::10"}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final byte[] CRYPT_KEY = {
|
||||||
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||||
|
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||||
|
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||||
|
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
|
||||||
|
};
|
||||||
|
private static final byte[] AUTH_KEY = {
|
||||||
|
0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
|
||||||
|
0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F
|
||||||
|
};
|
||||||
|
|
||||||
|
Context mMockContext;
|
||||||
|
INetd mMockNetd;
|
||||||
|
IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
|
||||||
|
IpSecService mIpSecService;
|
||||||
|
|
||||||
|
public IpSecServiceParameterizedTest(String remoteAddr) {
|
||||||
|
mRemoteAddr = remoteAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
mMockContext = mock(Context.class);
|
||||||
|
mMockNetd = mock(INetd.class);
|
||||||
|
mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
|
||||||
|
mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
|
||||||
|
|
||||||
|
// Injecting mock netd
|
||||||
|
when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIpSecServiceReserveSpi() throws Exception {
|
||||||
|
when(mMockNetd.ipSecAllocateSpi(
|
||||||
|
anyInt(),
|
||||||
|
eq(IpSecTransform.DIRECTION_OUT),
|
||||||
|
anyString(),
|
||||||
|
eq(mRemoteAddr),
|
||||||
|
eq(DROID_SPI)))
|
||||||
|
.thenReturn(DROID_SPI);
|
||||||
|
|
||||||
|
IpSecSpiResponse spiResp =
|
||||||
|
mIpSecService.reserveSecurityParameterIndex(
|
||||||
|
IpSecTransform.DIRECTION_OUT, mRemoteAddr, DROID_SPI, new Binder());
|
||||||
|
assertEquals(IpSecManager.Status.OK, spiResp.status);
|
||||||
|
assertEquals(DROID_SPI, spiResp.spi);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReleaseSecurityParameterIndex() throws Exception {
|
||||||
|
when(mMockNetd.ipSecAllocateSpi(
|
||||||
|
anyInt(),
|
||||||
|
eq(IpSecTransform.DIRECTION_OUT),
|
||||||
|
anyString(),
|
||||||
|
eq(mRemoteAddr),
|
||||||
|
eq(DROID_SPI)))
|
||||||
|
.thenReturn(DROID_SPI);
|
||||||
|
|
||||||
|
IpSecSpiResponse spiResp =
|
||||||
|
mIpSecService.reserveSecurityParameterIndex(
|
||||||
|
IpSecTransform.DIRECTION_OUT, mRemoteAddr, DROID_SPI, new Binder());
|
||||||
|
|
||||||
|
mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
|
||||||
|
|
||||||
|
verify(mMockNetd)
|
||||||
|
.ipSecDeleteSecurityAssociation(
|
||||||
|
eq(spiResp.resourceId), anyInt(), anyString(), anyString(), eq(DROID_SPI));
|
||||||
|
}
|
||||||
|
|
||||||
|
IpSecConfig buildIpSecConfig() throws Exception {
|
||||||
|
IpSecManager ipSecManager = new IpSecManager(mIpSecService);
|
||||||
|
|
||||||
|
// Mocking the netd to allocate SPI
|
||||||
|
when(mMockNetd.ipSecAllocateSpi(anyInt(), anyInt(), anyString(), anyString(), anyInt()))
|
||||||
|
.thenReturn(DROID_SPI)
|
||||||
|
.thenReturn(DROID_SPI2);
|
||||||
|
|
||||||
|
IpSecAlgorithm encryptAlgo = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
|
||||||
|
IpSecAlgorithm authAlgo =
|
||||||
|
new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 8);
|
||||||
|
|
||||||
|
/** Allocate and add SPI records in the IpSecService through IpSecManager interface. */
|
||||||
|
IpSecManager.SecurityParameterIndex outSpi =
|
||||||
|
ipSecManager.reserveSecurityParameterIndex(
|
||||||
|
IpSecTransform.DIRECTION_OUT,
|
||||||
|
NetworkUtils.numericToInetAddress(mRemoteAddr));
|
||||||
|
IpSecManager.SecurityParameterIndex inSpi =
|
||||||
|
ipSecManager.reserveSecurityParameterIndex(
|
||||||
|
IpSecTransform.DIRECTION_IN,
|
||||||
|
NetworkUtils.numericToInetAddress(mRemoteAddr));
|
||||||
|
|
||||||
|
IpSecConfig config = new IpSecConfig();
|
||||||
|
config.setSpiResourceId(IpSecTransform.DIRECTION_IN, inSpi.getResourceId());
|
||||||
|
config.setSpiResourceId(IpSecTransform.DIRECTION_OUT, outSpi.getResourceId());
|
||||||
|
config.setEncryption(IpSecTransform.DIRECTION_OUT, encryptAlgo);
|
||||||
|
config.setAuthentication(IpSecTransform.DIRECTION_OUT, authAlgo);
|
||||||
|
config.setEncryption(IpSecTransform.DIRECTION_IN, encryptAlgo);
|
||||||
|
config.setAuthentication(IpSecTransform.DIRECTION_IN, authAlgo);
|
||||||
|
config.setRemoteAddress(mRemoteAddr);
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateTransportModeTransform() throws Exception {
|
||||||
|
IpSecConfig ipSecConfig = buildIpSecConfig();
|
||||||
|
|
||||||
|
IpSecTransformResponse createTransformResp =
|
||||||
|
mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
|
||||||
|
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
|
||||||
|
|
||||||
|
verify(mMockNetd)
|
||||||
|
.ipSecAddSecurityAssociation(
|
||||||
|
eq(createTransformResp.resourceId),
|
||||||
|
anyInt(),
|
||||||
|
eq(IpSecTransform.DIRECTION_OUT),
|
||||||
|
anyString(),
|
||||||
|
anyString(),
|
||||||
|
anyLong(),
|
||||||
|
eq(DROID_SPI),
|
||||||
|
eq(IpSecAlgorithm.AUTH_HMAC_SHA256),
|
||||||
|
eq(AUTH_KEY),
|
||||||
|
anyInt(),
|
||||||
|
eq(IpSecAlgorithm.CRYPT_AES_CBC),
|
||||||
|
eq(CRYPT_KEY),
|
||||||
|
anyInt(),
|
||||||
|
anyInt(),
|
||||||
|
anyInt(),
|
||||||
|
anyInt());
|
||||||
|
verify(mMockNetd)
|
||||||
|
.ipSecAddSecurityAssociation(
|
||||||
|
eq(createTransformResp.resourceId),
|
||||||
|
anyInt(),
|
||||||
|
eq(IpSecTransform.DIRECTION_IN),
|
||||||
|
anyString(),
|
||||||
|
anyString(),
|
||||||
|
anyLong(),
|
||||||
|
eq(DROID_SPI2),
|
||||||
|
eq(IpSecAlgorithm.AUTH_HMAC_SHA256),
|
||||||
|
eq(AUTH_KEY),
|
||||||
|
anyInt(),
|
||||||
|
eq(IpSecAlgorithm.CRYPT_AES_CBC),
|
||||||
|
eq(CRYPT_KEY),
|
||||||
|
anyInt(),
|
||||||
|
anyInt(),
|
||||||
|
anyInt(),
|
||||||
|
anyInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteTransportModeTransform() throws Exception {
|
||||||
|
IpSecConfig ipSecConfig = buildIpSecConfig();
|
||||||
|
|
||||||
|
IpSecTransformResponse createTransformResp =
|
||||||
|
mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
|
||||||
|
mIpSecService.deleteTransportModeTransform(createTransformResp.resourceId);
|
||||||
|
|
||||||
|
verify(mMockNetd)
|
||||||
|
.ipSecDeleteSecurityAssociation(
|
||||||
|
eq(createTransformResp.resourceId),
|
||||||
|
eq(IpSecTransform.DIRECTION_OUT),
|
||||||
|
anyString(),
|
||||||
|
anyString(),
|
||||||
|
eq(DROID_SPI));
|
||||||
|
verify(mMockNetd)
|
||||||
|
.ipSecDeleteSecurityAssociation(
|
||||||
|
eq(createTransformResp.resourceId),
|
||||||
|
eq(IpSecTransform.DIRECTION_IN),
|
||||||
|
anyString(),
|
||||||
|
anyString(),
|
||||||
|
eq(DROID_SPI2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApplyTransportModeTransform() throws Exception {
|
||||||
|
IpSecConfig ipSecConfig = buildIpSecConfig();
|
||||||
|
|
||||||
|
IpSecTransformResponse createTransformResp =
|
||||||
|
mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
|
||||||
|
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
|
||||||
|
|
||||||
|
int resourceId = createTransformResp.resourceId;
|
||||||
|
mIpSecService.applyTransportModeTransform(pfd, resourceId);
|
||||||
|
|
||||||
|
verify(mMockNetd)
|
||||||
|
.ipSecApplyTransportModeTransform(
|
||||||
|
eq(pfd.getFileDescriptor()),
|
||||||
|
eq(resourceId),
|
||||||
|
eq(IpSecTransform.DIRECTION_OUT),
|
||||||
|
anyString(),
|
||||||
|
anyString(),
|
||||||
|
eq(DROID_SPI));
|
||||||
|
verify(mMockNetd)
|
||||||
|
.ipSecApplyTransportModeTransform(
|
||||||
|
eq(pfd.getFileDescriptor()),
|
||||||
|
eq(resourceId),
|
||||||
|
eq(IpSecTransform.DIRECTION_IN),
|
||||||
|
anyString(),
|
||||||
|
anyString(),
|
||||||
|
eq(DROID_SPI2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveTransportModeTransform() throws Exception {
|
||||||
|
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
|
||||||
|
mIpSecService.removeTransportModeTransform(pfd, 1);
|
||||||
|
|
||||||
|
verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd.getFileDescriptor());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,34 +23,28 @@ import static android.system.OsConstants.SOCK_DGRAM;
|
|||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.Matchers.anyInt;
|
|
||||||
import static org.mockito.Matchers.anyLong;
|
|
||||||
import static org.mockito.Matchers.anyObject;
|
|
||||||
import static org.mockito.Matchers.anyString;
|
|
||||||
import static org.mockito.Matchers.eq;
|
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.INetd;
|
import android.net.INetd;
|
||||||
import android.net.IpSecAlgorithm;
|
|
||||||
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.IpSecTransform;
|
||||||
import android.net.IpSecTransformResponse;
|
|
||||||
import android.net.IpSecUdpEncapResponse;
|
import android.net.IpSecUdpEncapResponse;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.support.test.filters.SmallTest;
|
import android.support.test.filters.SmallTest;
|
||||||
import android.system.ErrnoException;
|
import android.system.ErrnoException;
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -62,13 +56,8 @@ import org.junit.runners.JUnit4;
|
|||||||
public class IpSecServiceTest {
|
public class IpSecServiceTest {
|
||||||
|
|
||||||
private static final int DROID_SPI = 0xD1201D;
|
private static final int DROID_SPI = 0xD1201D;
|
||||||
private static final int DROID_SPI2 = DROID_SPI + 1;
|
|
||||||
private static final int TEST_UDP_ENCAP_INVALID_PORT = 100;
|
private static final int TEST_UDP_ENCAP_INVALID_PORT = 100;
|
||||||
private static final int TEST_UDP_ENCAP_PORT_OUT_RANGE = 100000;
|
private static final int TEST_UDP_ENCAP_PORT_OUT_RANGE = 100000;
|
||||||
private static final int TEST_UDP_ENCAP_PORT = 34567;
|
|
||||||
|
|
||||||
private static final String IPV4_LOOPBACK = "127.0.0.1";
|
|
||||||
private static final String IPV4_ADDR = "192.168.0.2";
|
|
||||||
|
|
||||||
private static final InetAddress INADDR_ANY;
|
private static final InetAddress INADDR_ANY;
|
||||||
|
|
||||||
@@ -80,21 +69,6 @@ public class IpSecServiceTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int[] DIRECTIONS =
|
|
||||||
new int[] {IpSecTransform.DIRECTION_OUT, IpSecTransform.DIRECTION_IN};
|
|
||||||
private static final byte[] CRYPT_KEY = {
|
|
||||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
||||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
|
||||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
|
||||||
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
|
|
||||||
};
|
|
||||||
private static final byte[] AUTH_KEY = {
|
|
||||||
0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
|
|
||||||
0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F
|
|
||||||
};
|
|
||||||
|
|
||||||
Context mMockContext;
|
Context mMockContext;
|
||||||
INetd mMockNetd;
|
INetd mMockNetd;
|
||||||
IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
|
IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
|
||||||
@@ -117,44 +91,6 @@ public class IpSecServiceTest {
|
|||||||
assertNotNull(ipSecSrv);
|
assertNotNull(ipSecSrv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIpSecServiceReserveSpi() throws Exception {
|
|
||||||
when(mMockNetd.ipSecAllocateSpi(
|
|
||||||
anyInt(),
|
|
||||||
eq(IpSecTransform.DIRECTION_OUT),
|
|
||||||
anyString(),
|
|
||||||
eq(IPV4_LOOPBACK),
|
|
||||||
eq(DROID_SPI)))
|
|
||||||
.thenReturn(DROID_SPI);
|
|
||||||
|
|
||||||
IpSecSpiResponse spiResp =
|
|
||||||
mIpSecService.reserveSecurityParameterIndex(
|
|
||||||
IpSecTransform.DIRECTION_OUT, IPV4_LOOPBACK, DROID_SPI, new Binder());
|
|
||||||
assertEquals(IpSecManager.Status.OK, spiResp.status);
|
|
||||||
assertEquals(DROID_SPI, spiResp.spi);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReleaseSecurityParameterIndex() throws Exception {
|
|
||||||
when(mMockNetd.ipSecAllocateSpi(
|
|
||||||
anyInt(),
|
|
||||||
eq(IpSecTransform.DIRECTION_OUT),
|
|
||||||
anyString(),
|
|
||||||
eq(IPV4_LOOPBACK),
|
|
||||||
eq(DROID_SPI)))
|
|
||||||
.thenReturn(DROID_SPI);
|
|
||||||
|
|
||||||
IpSecSpiResponse spiResp =
|
|
||||||
mIpSecService.reserveSecurityParameterIndex(
|
|
||||||
IpSecTransform.DIRECTION_OUT, IPV4_LOOPBACK, DROID_SPI, new Binder());
|
|
||||||
|
|
||||||
mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
|
|
||||||
|
|
||||||
verify(mMockNetd)
|
|
||||||
.ipSecDeleteSecurityAssociation(
|
|
||||||
eq(spiResp.resourceId), anyInt(), anyString(), anyString(), eq(DROID_SPI));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReleaseInvalidSecurityParameterIndex() throws Exception {
|
public void testReleaseInvalidSecurityParameterIndex() throws Exception {
|
||||||
try {
|
try {
|
||||||
@@ -285,108 +221,6 @@ public class IpSecServiceTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IpSecConfig buildIpSecConfig() throws Exception {
|
|
||||||
IpSecManager ipSecManager = new IpSecManager(mIpSecService);
|
|
||||||
|
|
||||||
// Mocking the netd to allocate SPI
|
|
||||||
when(mMockNetd.ipSecAllocateSpi(anyInt(), anyInt(), anyString(), anyString(), anyInt()))
|
|
||||||
.thenReturn(DROID_SPI)
|
|
||||||
.thenReturn(DROID_SPI2);
|
|
||||||
|
|
||||||
IpSecAlgorithm encryptAlgo = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
|
|
||||||
IpSecAlgorithm authAlgo =
|
|
||||||
new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 8);
|
|
||||||
|
|
||||||
InetAddress localAddr = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
|
|
||||||
|
|
||||||
/** Allocate and add SPI records in the IpSecService through IpSecManager interface. */
|
|
||||||
IpSecManager.SecurityParameterIndex outSpi =
|
|
||||||
ipSecManager.reserveSecurityParameterIndex(IpSecTransform.DIRECTION_OUT, localAddr);
|
|
||||||
IpSecManager.SecurityParameterIndex inSpi =
|
|
||||||
ipSecManager.reserveSecurityParameterIndex(IpSecTransform.DIRECTION_IN, localAddr);
|
|
||||||
|
|
||||||
IpSecConfig ipSecConfig =
|
|
||||||
new IpSecTransform.Builder(mMockContext)
|
|
||||||
.setSpi(IpSecTransform.DIRECTION_OUT, outSpi)
|
|
||||||
.setSpi(IpSecTransform.DIRECTION_IN, inSpi)
|
|
||||||
.setEncryption(IpSecTransform.DIRECTION_OUT, encryptAlgo)
|
|
||||||
.setAuthentication(IpSecTransform.DIRECTION_OUT, authAlgo)
|
|
||||||
.setEncryption(IpSecTransform.DIRECTION_IN, encryptAlgo)
|
|
||||||
.setAuthentication(IpSecTransform.DIRECTION_IN, authAlgo)
|
|
||||||
.getIpSecConfig();
|
|
||||||
return ipSecConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCreateTransportModeTransform() throws Exception {
|
|
||||||
IpSecConfig ipSecConfig = buildIpSecConfig();
|
|
||||||
|
|
||||||
IpSecTransformResponse createTransformResp =
|
|
||||||
mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
|
|
||||||
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
|
|
||||||
|
|
||||||
verify(mMockNetd)
|
|
||||||
.ipSecAddSecurityAssociation(
|
|
||||||
eq(createTransformResp.resourceId),
|
|
||||||
anyInt(),
|
|
||||||
eq(IpSecTransform.DIRECTION_OUT),
|
|
||||||
anyString(),
|
|
||||||
anyString(),
|
|
||||||
anyLong(),
|
|
||||||
eq(DROID_SPI),
|
|
||||||
eq(IpSecAlgorithm.AUTH_HMAC_SHA256),
|
|
||||||
eq(AUTH_KEY),
|
|
||||||
anyInt(),
|
|
||||||
eq(IpSecAlgorithm.CRYPT_AES_CBC),
|
|
||||||
eq(CRYPT_KEY),
|
|
||||||
anyInt(),
|
|
||||||
anyInt(),
|
|
||||||
anyInt(),
|
|
||||||
anyInt());
|
|
||||||
verify(mMockNetd)
|
|
||||||
.ipSecAddSecurityAssociation(
|
|
||||||
eq(createTransformResp.resourceId),
|
|
||||||
anyInt(),
|
|
||||||
eq(IpSecTransform.DIRECTION_IN),
|
|
||||||
anyString(),
|
|
||||||
anyString(),
|
|
||||||
anyLong(),
|
|
||||||
eq(DROID_SPI2),
|
|
||||||
eq(IpSecAlgorithm.AUTH_HMAC_SHA256),
|
|
||||||
eq(AUTH_KEY),
|
|
||||||
anyInt(),
|
|
||||||
eq(IpSecAlgorithm.CRYPT_AES_CBC),
|
|
||||||
eq(CRYPT_KEY),
|
|
||||||
anyInt(),
|
|
||||||
anyInt(),
|
|
||||||
anyInt(),
|
|
||||||
anyInt());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDeleteTransportModeTransform() throws Exception {
|
|
||||||
IpSecConfig ipSecConfig = buildIpSecConfig();
|
|
||||||
|
|
||||||
IpSecTransformResponse createTransformResp =
|
|
||||||
mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
|
|
||||||
mIpSecService.deleteTransportModeTransform(createTransformResp.resourceId);
|
|
||||||
|
|
||||||
verify(mMockNetd)
|
|
||||||
.ipSecDeleteSecurityAssociation(
|
|
||||||
eq(createTransformResp.resourceId),
|
|
||||||
eq(IpSecTransform.DIRECTION_OUT),
|
|
||||||
anyString(),
|
|
||||||
anyString(),
|
|
||||||
eq(DROID_SPI));
|
|
||||||
verify(mMockNetd)
|
|
||||||
.ipSecDeleteSecurityAssociation(
|
|
||||||
eq(createTransformResp.resourceId),
|
|
||||||
eq(IpSecTransform.DIRECTION_IN),
|
|
||||||
anyString(),
|
|
||||||
anyString(),
|
|
||||||
eq(DROID_SPI2));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteInvalidTransportModeTransform() throws Exception {
|
public void testDeleteInvalidTransportModeTransform() throws Exception {
|
||||||
try {
|
try {
|
||||||
@@ -396,35 +230,6 @@ public class IpSecServiceTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testApplyTransportModeTransform() throws Exception {
|
|
||||||
IpSecConfig ipSecConfig = buildIpSecConfig();
|
|
||||||
|
|
||||||
IpSecTransformResponse createTransformResp =
|
|
||||||
mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
|
|
||||||
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
|
|
||||||
|
|
||||||
int resourceId = createTransformResp.resourceId;
|
|
||||||
mIpSecService.applyTransportModeTransform(pfd, resourceId);
|
|
||||||
|
|
||||||
verify(mMockNetd)
|
|
||||||
.ipSecApplyTransportModeTransform(
|
|
||||||
eq(pfd.getFileDescriptor()),
|
|
||||||
eq(resourceId),
|
|
||||||
eq(IpSecTransform.DIRECTION_OUT),
|
|
||||||
anyString(),
|
|
||||||
anyString(),
|
|
||||||
eq(DROID_SPI));
|
|
||||||
verify(mMockNetd)
|
|
||||||
.ipSecApplyTransportModeTransform(
|
|
||||||
eq(pfd.getFileDescriptor()),
|
|
||||||
eq(resourceId),
|
|
||||||
eq(IpSecTransform.DIRECTION_IN),
|
|
||||||
anyString(),
|
|
||||||
anyString(),
|
|
||||||
eq(DROID_SPI2));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveTransportModeTransform() throws Exception {
|
public void testRemoveTransportModeTransform() throws Exception {
|
||||||
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
|
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
|
||||||
@@ -432,4 +237,25 @@ public class IpSecServiceTest {
|
|||||||
|
|
||||||
verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd.getFileDescriptor());
|
verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd.getFileDescriptor());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateIpAddresses() throws Exception {
|
||||||
|
String[] invalidAddresses =
|
||||||
|
new String[] {"www.google.com", "::", "2001::/64", "0.0.0.0", ""};
|
||||||
|
for (String address : invalidAddresses) {
|
||||||
|
try {
|
||||||
|
IpSecSpiResponse spiResp =
|
||||||
|
mIpSecService.reserveSecurityParameterIndex(
|
||||||
|
IpSecTransform.DIRECTION_OUT, address, DROID_SPI, new Binder());
|
||||||
|
fail("Invalid address was passed through IpSecService validation: " + address);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
} catch (Exception e) {
|
||||||
|
fail(
|
||||||
|
"Invalid InetAddress was not caught in validation: "
|
||||||
|
+ address
|
||||||
|
+ ", Exception: "
|
||||||
|
+ e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user