From 0febe5ece542cf16bc680e72d1484a3f603a18e0 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 22 Aug 2017 21:42:33 -0700 Subject: [PATCH] Add support for AES-GCM-ESP as an IPSec algorithm Allows native AES-GCM-ESP to be used as an IPSec transport/tunnel mode algorithm with kernel support Bug: 63589918 Test: IPsecService tests added, existing ones pass Change-Id: Ie1a9a902be205f269aa37bf956198f2e5b177c21 --- api/current.txt | 2 + api/system-current.txt | 2 + api/test-current.txt | 2 + core/java/android/net/IpSecAlgorithm.java | 24 ++- core/java/android/net/IpSecConfig.java | 20 ++ core/java/android/net/IpSecTransform.java | 27 +++ .../core/java/com/android/server/IpSecService.java | 14 +- .../server/IpSecServiceParameterizedTest.java | 237 ++++++++++++++++----- 8 files changed, 274 insertions(+), 54 deletions(-) diff --git a/api/current.txt b/api/current.txt index a0cd51b238f1..0b60cb81e807 100644 --- a/api/current.txt +++ b/api/current.txt @@ -25559,6 +25559,7 @@ package android.net { method public java.lang.String getName(); method public int getTruncationLengthBits(); method public void writeToParcel(android.os.Parcel, int); + field public static final java.lang.String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))"; field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)"; field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)"; field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)"; @@ -25606,6 +25607,7 @@ package android.net { public static class IpSecTransform.Builder { ctor public IpSecTransform.Builder(android.content.Context); method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException; + method public android.net.IpSecTransform.Builder setAuthenticatedEncryption(int, android.net.IpSecAlgorithm); method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm); method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm); method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int); diff --git a/api/system-current.txt b/api/system-current.txt index c9b656bad18f..e6ac1078b1fb 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -27755,6 +27755,7 @@ package android.net { method public java.lang.String getName(); method public int getTruncationLengthBits(); method public void writeToParcel(android.os.Parcel, int); + field public static final java.lang.String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))"; field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)"; field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)"; field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)"; @@ -27802,6 +27803,7 @@ package android.net { public static class IpSecTransform.Builder { ctor public IpSecTransform.Builder(android.content.Context); method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException; + method public android.net.IpSecTransform.Builder setAuthenticatedEncryption(int, android.net.IpSecAlgorithm); method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm); method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm); method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int); diff --git a/api/test-current.txt b/api/test-current.txt index 6936d5618f72..0e41fc1aeb9b 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -25668,6 +25668,7 @@ package android.net { method public java.lang.String getName(); method public int getTruncationLengthBits(); method public void writeToParcel(android.os.Parcel, int); + field public static final java.lang.String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))"; field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)"; field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)"; field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)"; @@ -25715,6 +25716,7 @@ package android.net { public static class IpSecTransform.Builder { ctor public IpSecTransform.Builder(android.content.Context); method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException; + method public android.net.IpSecTransform.Builder setAuthenticatedEncryption(int, android.net.IpSecAlgorithm); method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm); method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm); method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int); diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 79310e295a27..16b1452311a6 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -31,7 +31,6 @@ import java.util.Arrays; * RFC 4301. */ public final class IpSecAlgorithm implements Parcelable { - /** * AES-CBC Encryption/Ciphering Algorithm. * @@ -68,6 +67,7 @@ public final class IpSecAlgorithm implements Parcelable { *

Valid truncation lengths are multiples of 8 bits from 192 to (default) 384. */ public static final String AUTH_HMAC_SHA384 = "hmac(sha384)"; + /** * SHA512 HMAC Authentication/Integrity Algorithm * @@ -75,8 +75,24 @@ public final class IpSecAlgorithm implements Parcelable { */ public static final String AUTH_HMAC_SHA512 = "hmac(sha512)"; + /** + * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm. + * + *

Valid lengths for this key are {128, 192, 256}. + * + *

Valid ICV (truncation) lengths are {64, 96, 128}. + */ + public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))"; + /** @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, + AUTH_CRYPT_AES_GCM + }) @Retention(RetentionPolicy.SOURCE) public @interface AlgorithmName {} @@ -102,7 +118,7 @@ public final class IpSecAlgorithm implements Parcelable { * @param algoName precise name of the algorithm to be used. * @param key non-null Key padded to a multiple of 8 bits. * @param truncLenBits the number of bits of output hash to use; only meaningful for - * Authentication. + * Authentication or Authenticated Encryption (equivalent to ICV length). */ public IpSecAlgorithm(@AlgorithmName String algoName, byte[] key, int truncLenBits) { if (!isTruncationLengthValid(algoName, truncLenBits)) { @@ -175,6 +191,8 @@ public final class IpSecAlgorithm implements Parcelable { return (truncLenBits >= 192 && truncLenBits <= 384); case AUTH_HMAC_SHA512: return (truncLenBits >= 256 && truncLenBits <= 512); + case AUTH_CRYPT_AES_GCM: + return (truncLenBits == 64 || truncLenBits == 96 || truncLenBits == 128); default: return false; } diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index 632b7fc07f0c..61b13a922dd4 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -50,6 +50,9 @@ public final class IpSecConfig implements Parcelable { // Authentication Algorithm private IpSecAlgorithm mAuthentication; + // Authenticated Encryption Algorithm + private IpSecAlgorithm mAuthenticatedEncryption; + @Override public String toString() { return new StringBuilder() @@ -59,6 +62,8 @@ public final class IpSecConfig implements Parcelable { .append(mEncryption) .append(", mAuthentication=") .append(mAuthentication) + .append(", mAuthenticatedEncryption=") + .append(mAuthenticatedEncryption) .append("}") .toString(); } @@ -118,6 +123,11 @@ public final class IpSecConfig implements Parcelable { mFlow[direction].mAuthentication = authentication; } + /** Set the authenticated encryption algorithm for a given direction */ + public void setAuthenticatedEncryption(int direction, IpSecAlgorithm authenticatedEncryption) { + mFlow[direction].mAuthenticatedEncryption = authenticatedEncryption; + } + public void setNetwork(Network network) { mNetwork = network; } @@ -163,6 +173,10 @@ public final class IpSecConfig implements Parcelable { return mFlow[direction].mAuthentication; } + public IpSecAlgorithm getAuthenticatedEncryption(int direction) { + return mFlow[direction].mAuthenticatedEncryption; + } + public Network getNetwork() { return mNetwork; } @@ -199,9 +213,11 @@ public final class IpSecConfig implements Parcelable { out.writeInt(mFlow[IpSecTransform.DIRECTION_IN].mSpiResourceId); out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mEncryption, flags); out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mAuthentication, flags); + out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mAuthenticatedEncryption, flags); out.writeInt(mFlow[IpSecTransform.DIRECTION_OUT].mSpiResourceId); out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mEncryption, flags); out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mAuthentication, flags); + out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mAuthenticatedEncryption, flags); out.writeInt(mEncapType); out.writeInt(mEncapSocketResourceId); out.writeInt(mEncapRemotePort); @@ -221,11 +237,15 @@ public final class IpSecConfig implements Parcelable { (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); mFlow[IpSecTransform.DIRECTION_IN].mAuthentication = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); + mFlow[IpSecTransform.DIRECTION_IN].mAuthenticatedEncryption = + (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); mFlow[IpSecTransform.DIRECTION_OUT].mSpiResourceId = in.readInt(); mFlow[IpSecTransform.DIRECTION_OUT].mEncryption = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); mFlow[IpSecTransform.DIRECTION_OUT].mAuthentication = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); + mFlow[IpSecTransform.DIRECTION_OUT].mAuthenticatedEncryption = + (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); mEncapType = in.readInt(); mEncapSocketResourceId = in.readInt(); mEncapRemotePort = in.readInt(); diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index e15a2c672c20..48b5bd5c3d5b 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -281,6 +281,8 @@ public final class IpSecTransform implements AutoCloseable { *

If encryption is set for a given direction without also providing an SPI for that * direction, creation of an IpSecTransform will fail upon calling a build() method. * + *

Authenticated encryption is mutually exclusive with encryption and authentication. + * * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT} * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied. */ @@ -296,6 +298,8 @@ public final class IpSecTransform implements AutoCloseable { *

If authentication is set for a given direction without also providing an SPI for that * direction, creation of an IpSecTransform will fail upon calling a build() method. * + *

Authenticated encryption is mutually exclusive with encryption and authentication. + * * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT} * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied. */ @@ -306,6 +310,29 @@ public final class IpSecTransform implements AutoCloseable { } /** + * Add an authenticated encryption algorithm to the transform for the given direction. + * + *

If an authenticated encryption algorithm is set for a given direction without also + * providing an SPI for that direction, creation of an IpSecTransform will fail upon calling + * a build() method. + * + *

The Authenticated Encryption (AE) class of algorithms are also known as Authenticated + * Encryption with Associated Data (AEAD) algorithms, or Combined mode algorithms (as + * referred to in RFC 4301) + * + *

Authenticated encryption is mutually exclusive with encryption and authentication. + * + * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT} + * @param algo {@link IpSecAlgorithm} specifying the authenticated encryption algorithm to + * be applied. + */ + public IpSecTransform.Builder setAuthenticatedEncryption( + @TransformDirection int direction, IpSecAlgorithm algo) { + mConfig.setAuthenticatedEncryption(direction, algo); + return this; + } + + /** * Set the SPI, which uniquely identifies a particular IPsec session from others. Because * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a * given destination address. diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 2e1f142a7d19..cf1d33c86173 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -882,8 +882,14 @@ public class IpSecService extends IIpSecService.Stub { 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"); + 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"); } if (mSpiRecords.getAndCheckOwner(config.getSpiResourceId(direction)) == null) { @@ -922,6 +928,7 @@ public class IpSecService extends IIpSecService.Stub { for (int direction : DIRECTIONS) { IpSecAlgorithm auth = c.getAuthentication(direction); IpSecAlgorithm crypt = c.getEncryption(direction); + IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption(direction); spis[direction] = mSpiRecords.getAndCheckOwner(c.getSpiResourceId(direction)); int spi = spis[direction].getSpi(); @@ -942,6 +949,9 @@ public class IpSecService extends IIpSecService.Stub { (crypt != null) ? crypt.getName() : "", (crypt != null) ? crypt.getKey() : null, (crypt != null) ? crypt.getTruncationLengthBits() : 0, + (authCrypt != null) ? authCrypt.getName() : "", + (authCrypt != null) ? authCrypt.getKey() : null, + (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0, encapType, encapLocalPort, encapRemotePort); diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java index 9057a108dec4..b4b809480ffb 100644 --- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java +++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java @@ -17,10 +17,12 @@ package com.android.server; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; 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.Matchers.isNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -37,7 +39,6 @@ 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; @@ -53,8 +54,8 @@ import org.junit.runners.Parameterized; @RunWith(Parameterized.class) public class IpSecServiceParameterizedTest { - private static final int DROID_SPI = 0xD1201D; - private static final int DROID_SPI2 = DROID_SPI + 1; + private static final int TEST_SPI_OUT = 0xD1201D; + private static final int TEST_SPI_IN = TEST_SPI_OUT + 1; private final String mRemoteAddr; @@ -81,6 +82,16 @@ public class IpSecServiceParameterizedTest { IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig; IpSecService mIpSecService; + 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, CRYPT_KEY, CRYPT_KEY.length * 4); + + private static final int[] DIRECTIONS = + new int[] {IpSecTransform.DIRECTION_IN, IpSecTransform.DIRECTION_OUT}; + public IpSecServiceParameterizedTest(String remoteAddr) { mRemoteAddr = remoteAddr; } @@ -103,14 +114,14 @@ public class IpSecServiceParameterizedTest { eq(IpSecTransform.DIRECTION_OUT), anyString(), eq(mRemoteAddr), - eq(DROID_SPI))) - .thenReturn(DROID_SPI); + eq(TEST_SPI_OUT))) + .thenReturn(TEST_SPI_OUT); IpSecSpiResponse spiResp = mIpSecService.reserveSecurityParameterIndex( - IpSecTransform.DIRECTION_OUT, mRemoteAddr, DROID_SPI, new Binder()); + IpSecTransform.DIRECTION_OUT, mRemoteAddr, TEST_SPI_OUT, new Binder()); assertEquals(IpSecManager.Status.OK, spiResp.status); - assertEquals(DROID_SPI, spiResp.spi); + assertEquals(TEST_SPI_OUT, spiResp.spi); } @Test @@ -120,56 +131,60 @@ public class IpSecServiceParameterizedTest { eq(IpSecTransform.DIRECTION_OUT), anyString(), eq(mRemoteAddr), - eq(DROID_SPI))) - .thenReturn(DROID_SPI); + eq(TEST_SPI_OUT))) + .thenReturn(TEST_SPI_OUT); IpSecSpiResponse spiResp = mIpSecService.reserveSecurityParameterIndex( - IpSecTransform.DIRECTION_OUT, mRemoteAddr, DROID_SPI, new Binder()); + IpSecTransform.DIRECTION_OUT, mRemoteAddr, TEST_SPI_OUT, new Binder()); mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId); verify(mMockNetd) .ipSecDeleteSecurityAssociation( - eq(spiResp.resourceId), anyInt(), anyString(), anyString(), eq(DROID_SPI)); + eq(spiResp.resourceId), + anyInt(), + anyString(), + anyString(), + eq(TEST_SPI_OUT)); } - IpSecConfig buildIpSecConfig() throws Exception { - IpSecManager ipSecManager = new IpSecManager(mIpSecService); - - // Mocking the netd to allocate SPI + private int getNewSpiResourceId(int direction, String remoteAddress, int returnSpi) + throws Exception { 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); + .thenReturn(returnSpi); + + IpSecSpiResponse spi = + mIpSecService.reserveSecurityParameterIndex( + direction, + NetworkUtils.numericToInetAddress(remoteAddress).getHostAddress(), + IpSecManager.INVALID_SECURITY_PARAMETER_INDEX, + new Binder()); + return spi.resourceId; + } + + private void addDefaultSpisAndRemoteAddrToIpSecConfig(IpSecConfig config) throws Exception { + config.setSpiResourceId( + IpSecTransform.DIRECTION_OUT, + getNewSpiResourceId(IpSecTransform.DIRECTION_OUT, mRemoteAddr, TEST_SPI_OUT)); + config.setSpiResourceId( + IpSecTransform.DIRECTION_IN, + getNewSpiResourceId(IpSecTransform.DIRECTION_IN, mRemoteAddr, TEST_SPI_IN)); config.setRemoteAddress(mRemoteAddr); - return config; + } + + private void addAuthAndCryptToIpSecConfig(IpSecConfig config) throws Exception { + for (int direction : DIRECTIONS) { + config.setEncryption(direction, CRYPT_ALGO); + config.setAuthentication(direction, AUTH_ALGO); + } } @Test public void testCreateTransportModeTransform() throws Exception { - IpSecConfig ipSecConfig = buildIpSecConfig(); + IpSecConfig ipSecConfig = new IpSecConfig(); + addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig); + addAuthAndCryptToIpSecConfig(ipSecConfig); IpSecTransformResponse createTransformResp = mIpSecService.createTransportModeTransform(ipSecConfig, new Binder()); @@ -183,13 +198,16 @@ public class IpSecServiceParameterizedTest { anyString(), anyString(), anyLong(), - eq(DROID_SPI), + eq(TEST_SPI_OUT), eq(IpSecAlgorithm.AUTH_HMAC_SHA256), eq(AUTH_KEY), anyInt(), eq(IpSecAlgorithm.CRYPT_AES_CBC), eq(CRYPT_KEY), anyInt(), + eq(""), + isNull(), + eq(0), anyInt(), anyInt(), anyInt()); @@ -201,21 +219,140 @@ public class IpSecServiceParameterizedTest { anyString(), anyString(), anyLong(), - eq(DROID_SPI2), + eq(TEST_SPI_IN), eq(IpSecAlgorithm.AUTH_HMAC_SHA256), eq(AUTH_KEY), anyInt(), eq(IpSecAlgorithm.CRYPT_AES_CBC), eq(CRYPT_KEY), anyInt(), + eq(""), + isNull(), + eq(0), + anyInt(), + anyInt(), + anyInt()); + } + + @Test + public void testCreateTransportModeTransformAead() throws Exception { + IpSecConfig ipSecConfig = new IpSecConfig(); + addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig); + + ipSecConfig.setAuthenticatedEncryption(IpSecTransform.DIRECTION_OUT, AEAD_ALGO); + ipSecConfig.setAuthenticatedEncryption(IpSecTransform.DIRECTION_IN, AEAD_ALGO); + + 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(TEST_SPI_OUT), + eq(""), + isNull(), + eq(0), + eq(""), + isNull(), + eq(0), + eq(IpSecAlgorithm.AUTH_CRYPT_AES_GCM), + eq(CRYPT_KEY), + anyInt(), + anyInt(), + anyInt(), + anyInt()); + verify(mMockNetd) + .ipSecAddSecurityAssociation( + eq(createTransformResp.resourceId), + anyInt(), + eq(IpSecTransform.DIRECTION_IN), + anyString(), + anyString(), + anyLong(), + eq(TEST_SPI_IN), + eq(""), + isNull(), + eq(0), + eq(""), + isNull(), + eq(0), + eq(IpSecAlgorithm.AUTH_CRYPT_AES_GCM), + eq(CRYPT_KEY), + anyInt(), anyInt(), anyInt(), 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 = buildIpSecConfig(); + IpSecConfig ipSecConfig = new IpSecConfig(); + addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig); + addAuthAndCryptToIpSecConfig(ipSecConfig); IpSecTransformResponse createTransformResp = mIpSecService.createTransportModeTransform(ipSecConfig, new Binder()); @@ -227,19 +364,21 @@ public class IpSecServiceParameterizedTest { eq(IpSecTransform.DIRECTION_OUT), anyString(), anyString(), - eq(DROID_SPI)); + eq(TEST_SPI_OUT)); verify(mMockNetd) .ipSecDeleteSecurityAssociation( eq(createTransformResp.resourceId), eq(IpSecTransform.DIRECTION_IN), anyString(), anyString(), - eq(DROID_SPI2)); + eq(TEST_SPI_IN)); } @Test public void testApplyTransportModeTransform() throws Exception { - IpSecConfig ipSecConfig = buildIpSecConfig(); + IpSecConfig ipSecConfig = new IpSecConfig(); + addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig); + addAuthAndCryptToIpSecConfig(ipSecConfig); IpSecTransformResponse createTransformResp = mIpSecService.createTransportModeTransform(ipSecConfig, new Binder()); @@ -255,7 +394,7 @@ public class IpSecServiceParameterizedTest { eq(IpSecTransform.DIRECTION_OUT), anyString(), anyString(), - eq(DROID_SPI)); + eq(TEST_SPI_OUT)); verify(mMockNetd) .ipSecApplyTransportModeTransform( eq(pfd.getFileDescriptor()), @@ -263,7 +402,7 @@ public class IpSecServiceParameterizedTest { eq(IpSecTransform.DIRECTION_IN), anyString(), anyString(), - eq(DROID_SPI2)); + eq(TEST_SPI_IN)); } @Test -- 2.11.0