From 53d60a2d243b6cd3ad6dcb18ce84201462fb66c5 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 --- core/java/android/net/IpSecAlgorithm.java | 24 ++++++++++++++--- core/java/android/net/IpSecConfig.java | 20 ++++++++++++++ core/java/android/net/IpSecTransform.java | 27 +++++++++++++++++++ .../java/com/android/server/IpSecService.java | 14 ++++++++-- 4 files changed, 80 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 79310e295a..16b1452311 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 632b7fc07f..61b13a922d 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 e15a2c672c..48b5bd5c3d 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. */ @@ -305,6 +309,29 @@ public final class IpSecTransform implements AutoCloseable { return this; } + /** + * 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 diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 2e1f142a7d..cf1d33c861 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);