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

Commit 4f25570a authored by Benedict Wong's avatar Benedict Wong
Browse files

Add validation to IpSecConfig algorithm setters

Adds checks to ensure that users can only set the correct types of
algorithms for the Authentication, Encryption and Authenticated
Encryption algorithms.

Bug: 65223935
Test: Added tests in IpSecConfigTest, and passed on aosp_marlin-eng
Change-Id: I462c77d9eb5710b8d03a48866453649d3b6fc6bf
parent 693d8a2a
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -231,6 +231,31 @@ public final class IpSecAlgorithm implements Parcelable {
        }
    }

    /** @hide */
    public boolean isAuthentication() {
        switch (getName()) {
            // Fallthrough
            case AUTH_HMAC_MD5:
            case AUTH_HMAC_SHA1:
            case AUTH_HMAC_SHA256:
            case AUTH_HMAC_SHA384:
            case AUTH_HMAC_SHA512:
                return true;
            default:
                return false;
        }
    }

    /** @hide */
    public boolean isEncryption() {
        return getName().equals(CRYPT_AES_CBC);
    }

    /** @hide */
    public boolean isAead() {
        return getName().equals(AUTH_CRYPT_AES_GCM);
    }

    @Override
    public String toString() {
        return new StringBuilder()
+26 −11
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ import android.util.SparseArray;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;

import java.io.FileDescriptor;
import java.io.IOException;
@@ -1023,6 +1024,30 @@ public class IpSecService extends IIpSecService.Stub {
        releaseResource(userRecord.mEncapSocketRecords, resourceId);
    }

    @VisibleForTesting
    void validateAlgorithms(IpSecConfig config, int direction) throws IllegalArgumentException {
            IpSecAlgorithm auth = config.getAuthentication(direction);
            IpSecAlgorithm crypt = config.getEncryption(direction);
            IpSecAlgorithm aead = config.getAuthenticatedEncryption(direction);

            // Validate the algorithm set
            Preconditions.checkArgument(
                    aead != null || crypt != null || auth != null,
                    "No Encryption or Authentication algorithms specified");
            Preconditions.checkArgument(
                    auth == null || auth.isAuthentication(),
                    "Unsupported algorithm for Authentication");
            Preconditions.checkArgument(
                crypt == null || crypt.isEncryption(), "Unsupported algorithm for Encryption");
            Preconditions.checkArgument(
                    aead == null || aead.isAead(),
                    "Unsupported algorithm for Authenticated Encryption");
            Preconditions.checkArgument(
                    aead == null || (auth == null && crypt == null),
                    "Authenticated Encryption is mutually exclusive with other Authentication "
                                    + "or Encryption algorithms");
    }

    /**
     * Checks an IpSecConfig parcel to ensure that the contents are sane and throws an
     * IllegalArgumentException if they are not.
@@ -1072,17 +1097,7 @@ public class IpSecService extends IIpSecService.Stub {
        }

        for (int direction : DIRECTIONS) {
            IpSecAlgorithm crypt = config.getEncryption(direction);
            IpSecAlgorithm auth = config.getAuthentication(direction);
            IpSecAlgorithm authenticatedEncryption = config.getAuthenticatedEncryption(direction);
            if (authenticatedEncryption == null && crypt == null && auth == null) {
                throw new IllegalArgumentException(
                        "No Encryption or Authentication algorithms specified");
            } else if (authenticatedEncryption != null && (auth != null || crypt != null)) {
                throw new IllegalArgumentException(
                        "Authenticated Encryption is mutually"
                                + " exclusive with other Authentication or Encryption algorithms");
            }
            validateAlgorithms(config, direction);

            // Retrieve SPI record; will throw IllegalArgumentException if not found
            userRecord.mSpiRecords.getResourceOrThrow(config.getSpiResourceId(direction));
+0 −58
Original line number Diff line number Diff line
@@ -347,64 +347,6 @@ public class IpSecServiceParameterizedTest {
                        anyInt());
    }

    @Test
    public void testCreateInvalidConfigAeadWithAuth() throws Exception {
        IpSecConfig ipSecConfig = new IpSecConfig();
        addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);

        for (int direction : DIRECTIONS) {
            ipSecConfig.setAuthentication(direction, AUTH_ALGO);
            ipSecConfig.setAuthenticatedEncryption(direction, AEAD_ALGO);
        }

        try {
            mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
            fail(
                    "IpSecService should have thrown an error on authentication being"
                            + " enabled with authenticated encryption");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testCreateInvalidConfigAeadWithCrypt() throws Exception {
        IpSecConfig ipSecConfig = new IpSecConfig();
        addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);

        for (int direction : DIRECTIONS) {
            ipSecConfig.setEncryption(direction, CRYPT_ALGO);
            ipSecConfig.setAuthenticatedEncryption(direction, AEAD_ALGO);
        }

        try {
            mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
            fail(
                    "IpSecService should have thrown an error on encryption being"
                            + " enabled with authenticated encryption");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testCreateInvalidConfigAeadWithAuthAndCrypt() throws Exception {
        IpSecConfig ipSecConfig = new IpSecConfig();
        addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);

        for (int direction : DIRECTIONS) {
            ipSecConfig.setAuthentication(direction, AUTH_ALGO);
            ipSecConfig.setEncryption(direction, CRYPT_ALGO);
            ipSecConfig.setAuthenticatedEncryption(direction, AEAD_ALGO);
        }

        try {
            mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
            fail(
                    "IpSecService should have thrown an error on authentication and encryption being"
                            + " enabled with authenticated encryption");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testDeleteTransportModeTransform() throws Exception {
        IpSecConfig ipSecConfig = new IpSecConfig();
+153 −0
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@ 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;
@@ -76,6 +78,36 @@ public class IpSecServiceTest {

    private static final InetAddress INADDR_ANY;

    private static final byte[] AEAD_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,
        0x73, 0x61, 0x6C, 0x74
    };
    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
    };

    private static final IpSecAlgorithm AUTH_ALGO =
            new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
    private static final IpSecAlgorithm CRYPT_ALGO =
            new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
    private static final IpSecAlgorithm AEAD_ALGO =
            new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);

    private static final int[] DIRECTIONS =
            new int[] {IpSecTransform.DIRECTION_IN, IpSecTransform.DIRECTION_OUT};

    static {
        try {
            INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0});
@@ -269,6 +301,127 @@ public class IpSecServiceTest {
        }
    }

    @Test
    public void testValidateAlgorithmsAuth() {
        for (int direction : DIRECTIONS) {
            // Validate that correct algorithm type succeeds
            IpSecConfig config = new IpSecConfig();
            config.setAuthentication(direction, AUTH_ALGO);
            mIpSecService.validateAlgorithms(config, direction);

            // Validate that incorrect algorithm types fails
            for (IpSecAlgorithm algo : new IpSecAlgorithm[] {CRYPT_ALGO, AEAD_ALGO}) {
                try {
                    config = new IpSecConfig();
                    config.setAuthentication(direction, algo);
                    mIpSecService.validateAlgorithms(config, direction);
                    fail("Did not throw exception on invalid algorithm type");
                } catch (IllegalArgumentException expected) {
                }
            }
        }
    }

    @Test
    public void testValidateAlgorithmsCrypt() {
        for (int direction : DIRECTIONS) {
            // Validate that correct algorithm type succeeds
            IpSecConfig config = new IpSecConfig();
            config.setEncryption(direction, CRYPT_ALGO);
            mIpSecService.validateAlgorithms(config, direction);

            // Validate that incorrect algorithm types fails
            for (IpSecAlgorithm algo : new IpSecAlgorithm[] {AUTH_ALGO, AEAD_ALGO}) {
                try {
                    config = new IpSecConfig();
                    config.setEncryption(direction, algo);
                    mIpSecService.validateAlgorithms(config, direction);
                    fail("Did not throw exception on invalid algorithm type");
                } catch (IllegalArgumentException expected) {
                }
            }
        }
    }

    @Test
    public void testValidateAlgorithmsAead() {
        for (int direction : DIRECTIONS) {
            // Validate that correct algorithm type succeeds
            IpSecConfig config = new IpSecConfig();
            config.setAuthenticatedEncryption(direction, AEAD_ALGO);
            mIpSecService.validateAlgorithms(config, direction);

            // Validate that incorrect algorithm types fails
            for (IpSecAlgorithm algo : new IpSecAlgorithm[] {AUTH_ALGO, CRYPT_ALGO}) {
                try {
                    config = new IpSecConfig();
                    config.setAuthenticatedEncryption(direction, algo);
                    mIpSecService.validateAlgorithms(config, direction);
                    fail("Did not throw exception on invalid algorithm type");
                } catch (IllegalArgumentException expected) {
                }
            }
        }
    }

    @Test
    public void testValidateAlgorithmsAuthCrypt() {
        for (int direction : DIRECTIONS) {
            // Validate that correct algorithm type succeeds
            IpSecConfig config = new IpSecConfig();
            config.setAuthentication(direction, AUTH_ALGO);
            config.setEncryption(direction, CRYPT_ALGO);
            mIpSecService.validateAlgorithms(config, direction);
        }
    }

    @Test
    public void testValidateAlgorithmsNoAlgorithms() {
        IpSecConfig config = new IpSecConfig();
        try {
            mIpSecService.validateAlgorithms(config, IpSecTransform.DIRECTION_IN);
            fail("Expected exception; no algorithms specified");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testValidateAlgorithmsAeadWithAuth() {
        IpSecConfig config = new IpSecConfig();
        config.setAuthenticatedEncryption(IpSecTransform.DIRECTION_IN, AEAD_ALGO);
        config.setAuthentication(IpSecTransform.DIRECTION_IN, AUTH_ALGO);
        try {
            mIpSecService.validateAlgorithms(config, IpSecTransform.DIRECTION_IN);
            fail("Expected exception; both AEAD and auth algorithm specified");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testValidateAlgorithmsAeadWithCrypt() {
        IpSecConfig config = new IpSecConfig();
        config.setAuthenticatedEncryption(IpSecTransform.DIRECTION_IN, AEAD_ALGO);
        config.setEncryption(IpSecTransform.DIRECTION_IN, CRYPT_ALGO);
        try {
            mIpSecService.validateAlgorithms(config, IpSecTransform.DIRECTION_IN);
            fail("Expected exception; both AEAD and crypt algorithm specified");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testValidateAlgorithmsAeadWithAuthAndCrypt() {
        IpSecConfig config = new IpSecConfig();
        config.setAuthenticatedEncryption(IpSecTransform.DIRECTION_IN, AEAD_ALGO);
        config.setAuthentication(IpSecTransform.DIRECTION_IN, AUTH_ALGO);
        config.setEncryption(IpSecTransform.DIRECTION_IN, CRYPT_ALGO);
        try {
            mIpSecService.validateAlgorithms(config, IpSecTransform.DIRECTION_IN);
            fail("Expected exception; AEAD, auth and crypt algorithm specified");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testDeleteInvalidTransportModeTransform() throws Exception {
        try {