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

Commit a3d6e04d authored by Yan Yan's avatar Yan Yan
Browse files

Support converting EAP-TTLS to/from PersistableBundle

Bug: 163604823
Test: FrameworksVcnTests(add new tests)
Change-Id: I1e338d9c8940636b38f4725787de30fbbc1323ec
parent 3344f916
Loading
Loading
Loading
Loading
+46 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.vcn.persistablebundleutils;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Objects;

/**
 * CertUtils provides utility methods for constructing Certificate.
 *
 * @hide
 */
public class CertUtils {
    private static final String CERT_TYPE_X509 = "X.509";

    /** Decodes an ASN.1 DER encoded Certificate */
    public static X509Certificate certificateFromByteArray(byte[] derEncoded) {
        Objects.requireNonNull(derEncoded, "derEncoded is null");

        try {
            CertificateFactory certFactory = CertificateFactory.getInstance(CERT_TYPE_X509);
            InputStream in = new ByteArrayInputStream(derEncoded);
            return (X509Certificate) certFactory.generateCertificate(in);
        } catch (CertificateException e) {
            throw new IllegalArgumentException("Fail to decode certificate", e);
        }
    }
}
+62 −3
Original line number Diff line number Diff line
@@ -26,12 +26,15 @@ import android.net.eap.EapSessionConfig.EapAkaPrimeConfig;
import android.net.eap.EapSessionConfig.EapMethodConfig;
import android.net.eap.EapSessionConfig.EapMsChapV2Config;
import android.net.eap.EapSessionConfig.EapSimConfig;
import android.net.eap.EapSessionConfig.EapTtlsConfig;
import android.net.eap.EapSessionConfig.EapUiccConfig;
import android.os.PersistableBundle;

import com.android.internal.annotations.VisibleForTesting;
import com.android.server.vcn.util.PersistableBundleUtils;

import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.Objects;

/**
@@ -43,6 +46,7 @@ import java.util.Objects;
public final class EapSessionConfigUtils {
    private static final String EAP_ID_KEY = "EAP_ID_KEY";
    private static final String EAP_SIM_CONFIG_KEY = "EAP_SIM_CONFIG_KEY";
    private static final String EAP_TTLS_CONFIG_KEY = "EAP_TTLS_CONFIG_KEY";
    private static final String EAP_AKA_CONFIG_KEY = "EAP_AKA_CONFIG_KEY";
    private static final String EAP_MSCHAP_V2_CONFIG_KEY = "EAP_MSCHAP_V2_CONFIG_KEY";
    private static final String EAP_AKA_PRIME_CONFIG_KEY = "EAP_AKA_PRIME_CONFIG_KEY";
@@ -61,6 +65,12 @@ public final class EapSessionConfigUtils {
                    EapSimConfigUtils.toPersistableBundle(config.getEapSimConfig()));
        }

        if (config.getEapTtlsConfig() != null) {
            result.putPersistableBundle(
                    EAP_TTLS_CONFIG_KEY,
                    EapTtlsConfigUtils.toPersistableBundle(config.getEapTtlsConfig()));
        }

        if (config.getEapAkaConfig() != null) {
            result.putPersistableBundle(
                    EAP_AKA_CONFIG_KEY,
@@ -79,8 +89,6 @@ public final class EapSessionConfigUtils {
                    EapAkaPrimeConfigUtils.toPersistableBundle(config.getEapAkaPrimeConfig()));
        }

        // TODO: Handle EAP-TTLS.

        return result;
    }

@@ -100,6 +108,11 @@ public final class EapSessionConfigUtils {
            EapSimConfigUtils.setBuilderByReadingPersistableBundle(simBundle, builder);
        }

        final PersistableBundle ttlsBundle = in.getPersistableBundle(EAP_TTLS_CONFIG_KEY);
        if (ttlsBundle != null) {
            EapTtlsConfigUtils.setBuilderByReadingPersistableBundle(ttlsBundle, builder);
        }

        final PersistableBundle akaBundle = in.getPersistableBundle(EAP_AKA_CONFIG_KEY);
        if (akaBundle != null) {
            EapAkaConfigUtils.setBuilderByReadingPersistableBundle(akaBundle, builder);
@@ -115,7 +128,6 @@ public final class EapSessionConfigUtils {
            EapAkaPrimeConfigUtils.setBuilderByReadingPersistableBundle(akaPrimeBundle, builder);
        }

        // TODO: Handle EAP-TTLS.
        return builder.build();
    }

@@ -214,4 +226,51 @@ public final class EapSessionConfigUtils {
            builder.setEapMsChapV2Config(in.getString(USERNAME_KEY), in.getString(PASSWORD_KEY));
        }
    }

    private static final class EapTtlsConfigUtils extends EapMethodConfigUtils {
        private static final String TRUST_CERT_KEY = "TRUST_CERT_KEY";
        private static final String EAP_SESSION_CONFIG_KEY = "EAP_SESSION_CONFIG_KEY";

        @NonNull
        public static PersistableBundle toPersistableBundle(@NonNull EapTtlsConfig config) {
            final PersistableBundle result = EapMethodConfigUtils.toPersistableBundle(config);
            try {
                if (config.getServerCaCert() != null) {
                    final PersistableBundle caBundle =
                            PersistableBundleUtils.fromByteArray(
                                    config.getServerCaCert().getEncoded());
                    result.putPersistableBundle(TRUST_CERT_KEY, caBundle);
                }
            } catch (CertificateEncodingException e) {
                throw new IllegalStateException("Fail to encode the certificate");
            }

            result.putPersistableBundle(
                    EAP_SESSION_CONFIG_KEY,
                    EapSessionConfigUtils.toPersistableBundle(config.getInnerEapSessionConfig()));

            return result;
        }

        public static void setBuilderByReadingPersistableBundle(
                @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) {
            Objects.requireNonNull(in, "PersistableBundle was null");

            final PersistableBundle caBundle = in.getPersistableBundle(TRUST_CERT_KEY);
            X509Certificate caCert = null;
            if (caBundle != null) {
                caCert =
                        CertUtils.certificateFromByteArray(
                                PersistableBundleUtils.toByteArray(caBundle));
            }

            final PersistableBundle eapSessionConfigBundle =
                    in.getPersistableBundle(EAP_SESSION_CONFIG_KEY);
            Objects.requireNonNull(eapSessionConfigBundle, "Inner EAP Session Config was null");
            final EapSessionConfig eapSessionConfig =
                    EapSessionConfigUtils.fromPersistableBundle(eapSessionConfigBundle);

            builder.setEapTtlsConfig(caCert, eapSessionConfig);
        }
    }
}
+20 −0
Original line number Diff line number Diff line
-----BEGIN CERTIFICATE-----
MIIDPjCCAiagAwIBAgIICrKLpR7LxlowDQYJKoZIhvcNAQELBQAwPTELMAkGA1UE
BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxHDAaBgNVBAMTE2NhLnRlc3QuYW5kcm9p
ZC5uZXQwHhcNMTkwNzE2MTcxNTUyWhcNMjkwNzEzMTcxNTUyWjA9MQswCQYDVQQG
EwJVUzEQMA4GA1UEChMHQW5kcm9pZDEcMBoGA1UEAxMTY2EudGVzdC5hbmRyb2lk
Lm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANsvTwad2Nie0VOy
Xb1VtHL0R760Jm4vr14JWMcX4oiE6jUdTNdXQ0CGb65wvulP2aEeukFH0D/cvBMR
Bv9+haEwo9/grIXg9ALNKp+GfuZYw/dfnUMHFn3g2+SUgP6BoMZc4lkHktjkDKxp
99Q6h4NP/ip1labkhBeB9+Z6l78LTixKRKspNITWASJed9bjzshYxKHi6dJy3maQ
1LwYKmK7PEGRpoDoT8yZhFbxsVDUojGnJKH1RLXVOn/psG6dI/+IsbTipAttj5zc
g2VAD56PZG2Jd+vsup+g4Dy72hyy242x5c/H2LKZn4X0B0B+IXyii/ZVc+DJldQ5
JqplOL8CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
HQYDVR0OBBYEFGYUzuvZUaVJl8mcxejuFiUNGcTfMA0GCSqGSIb3DQEBCwUAA4IB
AQDQYeqjvHsK2ZqSqxakDp0nu36Plbj48Wvx1ru7GW2faz7i0w/Zkxh06zniILCb
QJRjDebSTHc5SSbCFrRTvqagaLDhbH42/hQncWqIoJqW+pmznJET4JiBO0sqzm05
yQWsLI/h9Ir28Y2g5N+XPBU0VVVejQqH4iI0iwQx7y7ABssQ0Xa/K73VPbeGaKd6
Prt4wjJvTlIL2yE2+0MggJ3F2rNptL5SDpg3g+4/YQ6wVRBFil95kUqplEsCtU4P
t+8RghiEmsRx/8CywKfZ5Hex87ODhsSDmDApcefbd5gxoWVkqxZUkPcKwYv1ucm8
u4r44fj4/9W0Zeooav5Yoh1q
-----END CERTIFICATE-----
 No newline at end of file
+24 −0
Original line number Diff line number Diff line
@@ -23,13 +23,17 @@ import static org.junit.Assert.assertEquals;
import android.net.eap.EapSessionConfig;
import android.os.PersistableBundle;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -86,4 +90,24 @@ public class EapSessionConfigUtilsTest {

        verifyPersistableBundleEncodeDecodeIsLossless(config);
    }

    @Test
    public void testSetEapTtlsEncodeDecodeIsLossless() throws Exception {
        final InputStream inputStream =
                InstrumentationRegistry.getContext()
                        .getResources()
                        .getAssets()
                        .open("self-signed-ca.pem");
        final CertificateFactory factory = CertificateFactory.getInstance("X.509");
        final X509Certificate trustedCa =
                (X509Certificate) factory.generateCertificate(inputStream);

        final EapSessionConfig innerConfig =
                new EapSessionConfig.Builder().setEapMsChapV2Config(USERNAME, PASSWORD).build();

        final EapSessionConfig config =
                new EapSessionConfig.Builder().setEapTtlsConfig(trustedCa, innerConfig).build();

        verifyPersistableBundleEncodeDecodeIsLossless(config);
    }
}