Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9778c788 authored by nharold's avatar nharold Committed by Gerrit Code Review
Browse files

Merge changes from topic "ipsec-svc-cleanup"

* changes:
  Split IpSecServiceTest to add IPv6 Tests
  Add equals() for IpSecAlgorithm and IpSecConfig
  Input Validation for IpSecService
parents cfe51aab 2e9a5200
Loading
Loading
Loading
Loading
+10 −7
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import com.android.internal.util.HexDump;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;

/**
 * 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)";

    /** @hide */
    @StringDef({
        CRYPT_AES_CBC,
        AUTH_HMAC_MD5,
        AUTH_HMAC_SHA1,
        AUTH_HMAC_SHA256,
        AUTH_HMAC_SHA512
    })
    @StringDef({CRYPT_AES_CBC, AUTH_HMAC_MD5, AUTH_HMAC_SHA1, AUTH_HMAC_SHA256, AUTH_HMAC_SHA512})
    @Retention(RetentionPolicy.SOURCE)
    public @interface AlgorithmName {}

@@ -197,4 +192,12 @@ public final class IpSecAlgorithm implements Parcelable {
                .append("}")
                .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);
    }
};
+172 −101
Original line number Diff line number Diff line
@@ -17,105 +17,170 @@ package android.net;

import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
import java.net.InetAddress;
import java.net.UnknownHostException;

import com.android.internal.annotations.VisibleForTesting;

/** @hide */
public final class IpSecConfig implements Parcelable {
    private static final String TAG = "IpSecConfig";

    // MODE_TRANSPORT or MODE_TUNNEL
    int mode;
    private int mMode = IpSecTransform.MODE_TRANSPORT;

    // For tunnel mode
    InetAddress localAddress;
    // Needs to be valid only for tunnel mode
    // 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
    Network network;
    // The underlying network interface that represents the "gateway" Network
    // for outbound packets. It may also be used to select packets.
    private Network mNetwork;

    public static class Flow {
        // Minimum requirements for identifying a transform
        // SPI identifying the IPsec flow in packet processing
        // and a remote IP address
        int spiResourceId;
        private int mSpiResourceId = IpSecManager.INVALID_RESOURCE_ID;

        // Encryption Algorithm
        IpSecAlgorithm encryption;
        private IpSecAlgorithm mEncryption;

        // Authentication Algorithm
        IpSecAlgorithm authentication;
        private IpSecAlgorithm mAuthentication;

        @Override
        public String toString() {
            return new StringBuilder()
                    .append("{spiResourceId=")
                    .append(spiResourceId)
                    .append(", encryption=")
                    .append(encryption)
                    .append(", authentication=")
                    .append(authentication)
                    .append("{mSpiResourceId=")
                    .append(mSpiResourceId)
                    .append(", mEncryption=")
                    .append(mEncryption)
                    .append(", mAuthentication=")
                    .append(mAuthentication)
                    .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));
        }
    }

    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
    // IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE
    int encapType;
    int encapLocalPortResourceId;
    int encapRemotePort;
    private int mEncapType = IpSecTransform.ENCAP_NONE;
    private int mEncapSocketResourceId = IpSecManager.INVALID_RESOURCE_ID;
    private int mEncapRemotePort;

    // 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
    public int getMode() {
        return mode;
        return mMode;
    }

    public InetAddress getLocalAddress() {
        return localAddress;
    public String getLocalAddress() {
        return mLocalAddress;
    }

    public int getSpiResourceId(int direction) {
        return flow[direction].spiResourceId;
        return mFlow[direction].mSpiResourceId;
    }

    public InetAddress getRemoteAddress() {
        return remoteAddress;
    public String getRemoteAddress() {
        return mRemoteAddress;
    }

    public IpSecAlgorithm getEncryption(int direction) {
        return flow[direction].encryption;
        return mFlow[direction].mEncryption;
    }

    public IpSecAlgorithm getAuthentication(int direction) {
        return flow[direction].authentication;
        return mFlow[direction].mAuthentication;
    }

    public Network getNetwork() {
        return network;
        return mNetwork;
    }

    public int getEncapType() {
        return encapType;
        return mEncapType;
    }

    public int getEncapLocalResourceId() {
        return encapLocalPortResourceId;
    public int getEncapSocketResourceId() {
        return mEncapSocketResourceId;
    }

    public int getEncapRemotePort() {
        return encapRemotePort;
        return mEncapRemotePort;
    }

    public int getNattKeepaliveInterval() {
        return nattKeepaliveInterval;
        return mNattKeepaliveInterval;
    }

    // Parcelable Methods
@@ -127,82 +192,70 @@ public final class IpSecConfig implements Parcelable {

    @Override
    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.writeString((localAddress != null) ? localAddress.getHostAddress() : null);
        // TODO: Use a byte array or other better method for storing IPs that can also include scope
        out.writeString((remoteAddress != null) ? remoteAddress.getHostAddress() : null);
        out.writeParcelable(network, flags);
        out.writeInt(flow[IpSecTransform.DIRECTION_IN].spiResourceId);
        out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryption, flags);
        out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authentication, flags);
        out.writeInt(flow[IpSecTransform.DIRECTION_OUT].spiResourceId);
        out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryption, flags);
        out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authentication, flags);
        out.writeInt(encapType);
        out.writeInt(encapLocalPortResourceId);
        out.writeInt(encapRemotePort);
    }

    // Package Private: Used by the IpSecTransform.Builder;
    // there should be no public constructor for this object
    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;
        }
        out.writeInt(mMode);
        out.writeString(mLocalAddress);
        out.writeString(mRemoteAddress);
        out.writeParcelable(mNetwork, flags);
        out.writeInt(mFlow[IpSecTransform.DIRECTION_IN].mSpiResourceId);
        out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mEncryption, flags);
        out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mAuthentication, 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.writeInt(mEncapType);
        out.writeInt(mEncapSocketResourceId);
        out.writeInt(mEncapRemotePort);
        out.writeInt(mNattKeepaliveInterval);
    }

    @VisibleForTesting
    public IpSecConfig() {}

    private IpSecConfig(Parcel in) {
        localAddress = readInetAddressFromParcel(in);
        remoteAddress = readInetAddressFromParcel(in);
        network = (Network) in.readParcelable(Network.class.getClassLoader());
        flow[IpSecTransform.DIRECTION_IN].spiResourceId = in.readInt();
        flow[IpSecTransform.DIRECTION_IN].encryption =
        mMode = in.readInt();
        mLocalAddress = in.readString();
        mRemoteAddress = in.readString();
        mNetwork = (Network) in.readParcelable(Network.class.getClassLoader());
        mFlow[IpSecTransform.DIRECTION_IN].mSpiResourceId = in.readInt();
        mFlow[IpSecTransform.DIRECTION_IN].mEncryption =
                (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
        flow[IpSecTransform.DIRECTION_IN].authentication =
        mFlow[IpSecTransform.DIRECTION_IN].mAuthentication =
                (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
        flow[IpSecTransform.DIRECTION_OUT].spiResourceId = in.readInt();
        flow[IpSecTransform.DIRECTION_OUT].encryption =
        mFlow[IpSecTransform.DIRECTION_OUT].mSpiResourceId = in.readInt();
        mFlow[IpSecTransform.DIRECTION_OUT].mEncryption =
                (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
        flow[IpSecTransform.DIRECTION_OUT].authentication =
        mFlow[IpSecTransform.DIRECTION_OUT].mAuthentication =
                (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
        encapType = in.readInt();
        encapLocalPortResourceId = in.readInt();
        encapRemotePort = in.readInt();
        mEncapType = in.readInt();
        mEncapSocketResourceId = in.readInt();
        mEncapRemotePort = in.readInt();
        mNattKeepaliveInterval = in.readInt();
    }

    @Override
    public String toString() {
        StringBuilder strBuilder = new StringBuilder();
        strBuilder
                .append("{mode=")
                .append(mode == IpSecTransform.MODE_TUNNEL ? "TUNNEL" : "TRANSPORT")
                .append(", localAddress=")
                .append(localAddress)
                .append(", remoteAddress=")
                .append(remoteAddress)
                .append(", network=")
                .append(network)
                .append(", encapType=")
                .append(encapType)
                .append(", encapLocalPortResourceId=")
                .append(encapLocalPortResourceId)
                .append(", encapRemotePort=")
                .append(encapRemotePort)
                .append(", nattKeepaliveInterval=")
                .append(nattKeepaliveInterval)
                .append(", flow[OUT]=")
                .append(flow[IpSecTransform.DIRECTION_OUT])
                .append(", flow[IN]=")
                .append(flow[IpSecTransform.DIRECTION_IN])
                .append("{mMode=")
                .append(mMode == IpSecTransform.MODE_TUNNEL ? "TUNNEL" : "TRANSPORT")
                .append(", mLocalAddress=")
                .append(mLocalAddress)
                .append(", mRemoteAddress=")
                .append(mRemoteAddress)
                .append(", mNetwork=")
                .append(mNetwork)
                .append(", mEncapType=")
                .append(mEncapType)
                .append(", mEncapSocketResourceId=")
                .append(mEncapSocketResourceId)
                .append(", mEncapRemotePort=")
                .append(mEncapRemotePort)
                .append(", mNattKeepaliveInterval=")
                .append(mNattKeepaliveInterval)
                .append(", mFlow[OUT]=")
                .append(mFlow[IpSecTransform.DIRECTION_OUT])
                .append(", mFlow[IN]=")
                .append(mFlow[IpSecTransform.DIRECTION_IN])
                .append("}");

        return strBuilder.toString();
@@ -218,4 +271,22 @@ public final class IpSecConfig implements Parcelable {
                    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]));
    }
}
+6 −2
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ import android.os.RemoteException;
import android.util.AndroidException;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;

import dalvik.system.CloseGuard;

import java.io.FileDescriptor;
@@ -188,7 +190,8 @@ public final class IpSecManager {
        }

        /** @hide */
        int getResourceId() {
        @VisibleForTesting
        public int getResourceId() {
            return mResourceId;
        }
    }
@@ -489,7 +492,8 @@ public final class IpSecManager {
        }

        /** @hide */
        int getResourceId() {
        @VisibleForTesting
        public int getResourceId() {
            return mResourceId;
        }
    };
+27 −76
Original line number Diff line number Diff line
@@ -68,10 +68,10 @@ public final class IpSecTransform implements AutoCloseable {
    public @interface TransformDirection {}

    /** @hide */
    public static final int MODE_TUNNEL = 0;
    public static final int MODE_TRANSPORT = 0;

    /** @hide */
    public static final int MODE_TRANSPORT = 1;
    public static final int MODE_TUNNEL = 1;

    /** @hide */
    public static final int ENCAP_NONE = 0;
@@ -113,7 +113,11 @@ public final class IpSecTransform implements AutoCloseable {
        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,
                    IpSecManager.SpiUnavailableException {
        switch (status) {
@@ -141,7 +145,7 @@ public final class IpSecTransform implements AutoCloseable {
                IpSecTransformResponse result =
                        svc.createTransportModeTransform(mConfig, new Binder());
                int status = result.status;
                checkResultStatusAndThrow(status);
                checkResultStatus(status);
                mResourceId = result.resourceId;

                /* Keepalive will silently fail if not needed by the config; but, if needed and
@@ -243,62 +247,21 @@ public final class IpSecTransform implements AutoCloseable {

    /* Package */
    void startKeepalive(Context c) {
        // FIXME: NO_KEEPALIVE needs to be a constant
        if (mConfig.getNattKeepaliveInterval() == 0) {
            return;
        if (mConfig.getNattKeepaliveInterval() != 0) {
            Log.wtf(TAG, "Keepalive not yet supported.");
        }

        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 */
    int getResourceId() {
    /** @hide */
    @VisibleForTesting
    public int getResourceId() {
        return mResourceId;
    }

    /* Package */
    void stopKeepalive() {
        if (mKeepalive == null) {
        return;
    }
        mKeepalive.stop();
        synchronized (mKeepaliveSyncLock) {
            if (mKeepaliveStatus == ConnectivityManager.PacketKeepalive.SUCCESS) {
                try {
                    mKeepaliveSyncLock.wait(2000);
                } catch (InterruptedException e) {
                }
            }
        }
    }

    /**
     * Builder object to facilitate the creation of IpSecTransform objects.
@@ -323,7 +286,7 @@ public final class IpSecTransform implements AutoCloseable {
         */
        public IpSecTransform.Builder setEncryption(
                @TransformDirection int direction, IpSecAlgorithm algo) {
            mConfig.flow[direction].encryption = algo;
            mConfig.setEncryption(direction, algo);
            return this;
        }

@@ -338,7 +301,7 @@ public final class IpSecTransform implements AutoCloseable {
         */
        public IpSecTransform.Builder setAuthentication(
                @TransformDirection int direction, IpSecAlgorithm algo) {
            mConfig.flow[direction].authentication = algo;
            mConfig.setAuthentication(direction, algo);
            return this;
        }

@@ -361,9 +324,7 @@ public final class IpSecTransform implements AutoCloseable {
         */
        public IpSecTransform.Builder setSpi(
                @TransformDirection int direction, IpSecManager.SecurityParameterIndex spi) {
            // TODO: convert to using the resource Id of the SPI. Then build() can validate
            // the owner in the IpSecService
            mConfig.flow[direction].spiResourceId = spi.getResourceId();
            mConfig.setSpiResourceId(direction, spi.getResourceId());
            return this;
        }

@@ -378,7 +339,7 @@ public final class IpSecTransform implements AutoCloseable {
         */
        @SystemApi
        public IpSecTransform.Builder setUnderlyingNetwork(Network net) {
            mConfig.network = net;
            mConfig.setNetwork(net);
            return this;
        }

@@ -395,10 +356,9 @@ public final class IpSecTransform implements AutoCloseable {
         */
        public IpSecTransform.Builder setIpv4Encapsulation(
                IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) {
            // TODO: check encap type is valid.
            mConfig.encapType = ENCAP_ESPINUDP;
            mConfig.encapLocalPortResourceId = localSocket.getResourceId();
            mConfig.encapRemotePort = remotePort;
            mConfig.setEncapType(ENCAP_ESPINUDP);
            mConfig.setEncapSocketResourceId(localSocket.getResourceId());
            mConfig.setEncapRemotePort(remotePort);
            return this;
        }

@@ -416,7 +376,7 @@ public final class IpSecTransform implements AutoCloseable {
         */
        @SystemApi
        public IpSecTransform.Builder setNattKeepalive(int intervalSeconds) {
            mConfig.nattKeepaliveInterval = intervalSeconds;
            mConfig.setNattKeepaliveInterval(intervalSeconds);
            return this;
        }

@@ -451,8 +411,8 @@ public final class IpSecTransform implements AutoCloseable {
                        IpSecManager.SpiUnavailableException, IOException {
            //FIXME: argument validation here
            //throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation");
            mConfig.mode = MODE_TRANSPORT;
            mConfig.remoteAddress = remoteAddress;
            mConfig.setMode(MODE_TRANSPORT);
            mConfig.setRemoteAddress(remoteAddress.getHostAddress());
            return new IpSecTransform(mContext, mConfig).activate();
        }

@@ -473,9 +433,9 @@ public final class IpSecTransform implements AutoCloseable {
                InetAddress localAddress, InetAddress remoteAddress) {
            //FIXME: argument validation here
            //throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation");
            mConfig.localAddress = localAddress;
            mConfig.remoteAddress = remoteAddress;
            mConfig.mode = MODE_TUNNEL;
            mConfig.setLocalAddress(localAddress.getHostAddress());
            mConfig.setRemoteAddress(remoteAddress.getHostAddress());
            mConfig.setMode(MODE_TUNNEL);
            return new IpSecTransform(mContext, mConfig);
        }

@@ -489,14 +449,5 @@ public final class IpSecTransform implements AutoCloseable {
            mContext = context;
            mConfig = new IpSecConfig();
        }

        /**
         * Return an {@link IpSecConfig} object for testing purposes.
         * @hide
         */
        @VisibleForTesting
        public IpSecConfig getIpSecConfig() {
            return mConfig;
        }
    }
}
+122 −29

File changed.

Preview size limit exceeded, changes collapsed.

Loading