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

Commit b84954cf authored by Rubin Xu's avatar Rubin Xu Committed by Android Partner Code Review
Browse files

Merge "API to set multiple CA certificates for WifiEnterpriseConfig" into mm-wireless-dev

parents 4269239f a0e3d621
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -19218,6 +19218,7 @@ package android.net.wifi {
    method public java.lang.String getAltSubjectMatch();
    method public java.lang.String getAnonymousIdentity();
    method public java.security.cert.X509Certificate getCaCertificate();
    method public java.security.cert.X509Certificate[] getCaCertificates();
    method public java.security.cert.X509Certificate getClientCertificate();
    method public java.lang.String getDomainSuffixMatch();
    method public int getEapMethod();
@@ -19230,6 +19231,7 @@ package android.net.wifi {
    method public void setAltSubjectMatch(java.lang.String);
    method public void setAnonymousIdentity(java.lang.String);
    method public void setCaCertificate(java.security.cert.X509Certificate);
    method public void setCaCertificates(java.security.cert.X509Certificate[]);
    method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
    method public void setDomainSuffixMatch(java.lang.String);
    method public void setEapMethod(int);
+2 −0
Original line number Diff line number Diff line
@@ -20994,6 +20994,7 @@ package android.net.wifi {
    method public java.lang.String getAltSubjectMatch();
    method public java.lang.String getAnonymousIdentity();
    method public java.security.cert.X509Certificate getCaCertificate();
    method public java.security.cert.X509Certificate[] getCaCertificates();
    method public java.security.cert.X509Certificate getClientCertificate();
    method public java.lang.String getDomainSuffixMatch();
    method public int getEapMethod();
@@ -21006,6 +21007,7 @@ package android.net.wifi {
    method public void setAltSubjectMatch(java.lang.String);
    method public void setAnonymousIdentity(java.lang.String);
    method public void setCaCertificate(java.security.cert.X509Certificate);
    method public void setCaCertificates(java.security.cert.X509Certificate[]);
    method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
    method public void setDomainSuffixMatch(java.lang.String);
    method public void setEapMethod(int);
+174 −10
Original line number Diff line number Diff line
@@ -15,12 +15,14 @@
 */
package android.net.wifi;

import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import android.security.Credentials;
import android.text.TextUtils;

import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
@@ -71,6 +73,13 @@ public class WifiEnterpriseConfig implements Parcelable {
     */
    public static final String KEYSTORE_URI = "keystore://";

    /**
     * String representing the keystore URI used for wpa_supplicant,
     * Unlike #KEYSTORE_URI, this supports a list of space-delimited aliases
     * @hide
     */
    public static final String KEYSTORES_URI = "keystores://";

    /**
     * String to set the engine value to when it should be enabled.
     * @hide
@@ -103,6 +112,8 @@ public class WifiEnterpriseConfig implements Parcelable {
    public static final String PLMN_KEY            = "plmn";
    /** @hide */
    public static final String PHASE1_KEY          = "phase1";
    /** @hide */
    public static final String CA_CERT_ALIAS_DELIMITER = " ";

    /** {@hide} */
    public static final String ENABLE_TLS_1_2 = "\"tls_disable_tlsv1_2=0\"";
@@ -113,7 +124,7 @@ public class WifiEnterpriseConfig implements Parcelable {
    //By default, we enable TLS1.2. However, due to a known bug on some radius, we may disable it to
    // fall back to TLS 1.1.
    private boolean mTls12Enable =  true;
    private X509Certificate mCaCert;
    private X509Certificate[] mCaCerts;
    private PrivateKey mClientPrivateKey;
    private X509Certificate mClientCertificate;

@@ -145,7 +156,7 @@ public class WifiEnterpriseConfig implements Parcelable {
            dest.writeString(entry.getValue());
        }

        writeCertificate(dest, mCaCert);
        writeCertificates(dest, mCaCerts);

        if (mClientPrivateKey != null) {
            String algorithm = mClientPrivateKey.getAlgorithm();
@@ -161,6 +172,17 @@ public class WifiEnterpriseConfig implements Parcelable {
        dest.writeInt(mTls12Enable ? 1: 0);
    }

    private void writeCertificates(Parcel dest, X509Certificate[] cert) {
        if (cert != null && cert.length != 0) {
            dest.writeInt(cert.length);
            for (int i = 0; i < cert.length; i++) {
                writeCertificate(dest, cert[i]);
            }
        } else {
            dest.writeInt(0);
        }
    }

    private void writeCertificate(Parcel dest, X509Certificate cert) {
        if (cert != null) {
            try {
@@ -186,7 +208,7 @@ public class WifiEnterpriseConfig implements Parcelable {
                        enterpriseConfig.mFields.put(key, value);
                    }

                    enterpriseConfig.mCaCert = readCertificate(in);
                    enterpriseConfig.mCaCerts = readCertificates(in);

                    PrivateKey userKey = null;
                    int len = in.readInt();
@@ -210,6 +232,18 @@ public class WifiEnterpriseConfig implements Parcelable {
                    return enterpriseConfig;
                }

                private X509Certificate[] readCertificates(Parcel in) {
                    X509Certificate[] certs = null;
                    int len = in.readInt();
                    if (len > 0) {
                        certs = new X509Certificate[len];
                        for (int i = 0; i < len; i++) {
                            certs[i] = readCertificate(in);
                        }
                    }
                    return certs;
                }

                private X509Certificate readCertificate(Parcel in) {
                    X509Certificate cert = null;
                    int len = in.readInt();
@@ -429,6 +463,36 @@ public class WifiEnterpriseConfig implements Parcelable {
        return getFieldValue(PASSWORD_KEY, "");
    }

    /**
     * Encode a CA certificate alias so it does not contain illegal character.
     * @hide
     */
    public static String encodeCaCertificateAlias(String alias) {
        byte[] bytes = alias.getBytes(StandardCharsets.UTF_8);
        StringBuilder sb = new StringBuilder(bytes.length * 2);
        for (byte o : bytes) {
            sb.append(String.format("%02x", o & 0xFF));
        }
        return sb.toString();
    }

    /**
     * Decode a previously-encoded CA certificate alias.
     * @hide
     */
    public static String decodeCaCertificateAlias(String alias) {
        byte[] data = new byte[alias.length() >> 1];
        for (int n = 0, position = 0; n < alias.length(); n += 2, position++) {
            data[position] = (byte) Integer.parseInt(alias.substring(n,  n + 2), 16);
        }
        try {
            return new String(data, StandardCharsets.UTF_8);
        } catch (NumberFormatException e) {
            e.printStackTrace();
            return alias;
        }
    }

    /**
     * Set CA certificate alias.
     *
@@ -442,6 +506,35 @@ public class WifiEnterpriseConfig implements Parcelable {
        setFieldValue(CA_CERT_KEY, alias, CA_CERT_PREFIX);
    }

    /**
     * Set CA certificate aliases. When creating installing the corresponding certificate to
     * the keystore, please use alias encoded by {@link #encodeCaCertificateAlias(String)}.
     *
     * <p> See the {@link android.security.KeyChain} for details on installing or choosing
     * a certificate.
     * </p>
     * @param aliases identifies the certificate
     * @hide
     */
    public void setCaCertificateAliases(@Nullable String[] aliases) {
        if (aliases == null) {
            setFieldValue(CA_CERT_KEY, null, CA_CERT_PREFIX);
        } else if (aliases.length == 1) {
            // Backwards compatibility: use the original cert prefix if setting only one alias.
            setCaCertificateAlias(aliases[0]);
        } else {
            // Use KEYSTORES_URI which supports multiple aliases.
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < aliases.length; i++) {
                if (i > 0) {
                    sb.append(CA_CERT_ALIAS_DELIMITER);
                }
                sb.append(encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + aliases[i]));
            }
            setFieldValue(CA_CERT_KEY, sb.toString(), KEYSTORES_URI);
        }
    }

    /**
     * Get CA certificate alias
     * @return alias to the CA certificate
@@ -451,6 +544,32 @@ public class WifiEnterpriseConfig implements Parcelable {
        return getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX);
    }

    /**
     * Get CA certificate aliases
     * @return alias to the CA certificate
     * @hide
     */
    @Nullable public String[] getCaCertificateAliases() {
        String value = getFieldValue(CA_CERT_KEY, "");
        if (value.startsWith(CA_CERT_PREFIX)) {
            // Backwards compatibility: parse the original alias prefix.
            return new String[] {getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX)};
        } else if (value.startsWith(KEYSTORES_URI)) {
            String values = value.substring(KEYSTORES_URI.length());

            String[] aliases = TextUtils.split(values, CA_CERT_ALIAS_DELIMITER);
            for (int i = 0; i < aliases.length; i++) {
                aliases[i] = decodeCaCertificateAlias(aliases[i]);
                if (aliases[i].startsWith(Credentials.CA_CERTIFICATE)) {
                    aliases[i] = aliases[i].substring(Credentials.CA_CERTIFICATE.length());
                }
            }
            return aliases.length != 0 ? aliases : null;
        } else {
            return TextUtils.isEmpty(value) ? null : new String[] {value};
        }
    }

    /**
     * Specify a X.509 certificate that identifies the server.
     *
@@ -462,31 +581,76 @@ public class WifiEnterpriseConfig implements Parcelable {
     * @param cert X.509 CA certificate
     * @throws IllegalArgumentException if not a CA certificate
     */
    public void setCaCertificate(X509Certificate cert) {
    public void setCaCertificate(@Nullable X509Certificate cert) {
        if (cert != null) {
            if (cert.getBasicConstraints() >= 0) {
                mCaCert = cert;
                mCaCerts = new X509Certificate[] {cert};
            } else {
                throw new IllegalArgumentException("Not a CA certificate");
            }
        } else {
            mCaCert = null;
            mCaCerts = null;
        }
    }

    /**
     * Get CA certificate
     * Get CA certificate. If multiple CA certificates are configured previously,
     * return the first one.
     * @return X.509 CA certificate
     */
    public X509Certificate getCaCertificate() {
        return mCaCert;
    @Nullable public X509Certificate getCaCertificate() {
        if (mCaCerts != null && mCaCerts.length > 0) {
            return mCaCerts[0];
        } else {
            return null;
        }
    }

    /**
     * Specify a list of X.509 certificates that identifies the server. The validation
     * passes if the CA of server certificate matches one of the given certificates.

     * <p>Default names are automatically assigned to the certificates and used
     * with this configuration. The framework takes care of installing the
     * certificates when the config is saved and removing the certificates when
     * the config is removed.
     *
     * @param certs X.509 CA certificates
     * @throws IllegalArgumentException if any of the provided certificates is
     *     not a CA certificate
     */
    public void setCaCertificates(@Nullable X509Certificate[] certs) {
        if (certs != null) {
            X509Certificate[] newCerts = new X509Certificate[certs.length];
            for (int i = 0; i < certs.length; i++) {
                if (certs[i].getBasicConstraints() >= 0) {
                    newCerts[i] = certs[i];
                } else {
                    throw new IllegalArgumentException("Not a CA certificate");
                }
            }
            mCaCerts = newCerts;
        } else {
            mCaCerts = null;
        }
    }

    /**
     * Get CA certificates.
     */
    @Nullable public X509Certificate[] getCaCertificates() {
        if (mCaCerts != null || mCaCerts.length > 0) {
            return mCaCerts;
        } else {
            return null;
        }
    }

    /**
     * @hide
     */
    public void resetCaCertificate() {
        mCaCert = null;
        mCaCerts = null;
    }

    /** Set Client certificate alias.