Loading api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -23957,6 +23957,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(); Loading @@ -23969,6 +23970,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); api/system-current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -25839,6 +25839,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(); Loading @@ -25851,6 +25852,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); wifi/java/android/net/wifi/WifiEnterpriseConfig.java +174 −10 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -101,10 +110,12 @@ public class WifiEnterpriseConfig implements Parcelable { public static final String REALM_KEY = "realm"; /** @hide */ public static final String PLMN_KEY = "plmn"; /** @hide */ public static final String CA_CERT_ALIAS_DELIMITER = " "; private HashMap<String, String> mFields = new HashMap<String, String>(); private X509Certificate mCaCert; private X509Certificate[] mCaCerts; private PrivateKey mClientPrivateKey; private X509Certificate mClientCertificate; Loading Loading @@ -136,7 +147,7 @@ public class WifiEnterpriseConfig implements Parcelable { dest.writeString(entry.getValue()); } writeCertificate(dest, mCaCert); writeCertificates(dest, mCaCerts); if (mClientPrivateKey != null) { String algorithm = mClientPrivateKey.getAlgorithm(); Loading @@ -151,6 +162,17 @@ public class WifiEnterpriseConfig implements Parcelable { writeCertificate(dest, mClientCertificate); } 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 { Loading @@ -176,7 +198,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(); Loading @@ -199,6 +221,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(); Loading Loading @@ -398,6 +432,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. * Loading @@ -411,6 +475,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 Loading @@ -420,6 +513,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. * Loading @@ -431,31 +550,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. Loading Loading
api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -23957,6 +23957,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(); Loading @@ -23969,6 +23970,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);
api/system-current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -25839,6 +25839,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(); Loading @@ -25851,6 +25852,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);
wifi/java/android/net/wifi/WifiEnterpriseConfig.java +174 −10 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -101,10 +110,12 @@ public class WifiEnterpriseConfig implements Parcelable { public static final String REALM_KEY = "realm"; /** @hide */ public static final String PLMN_KEY = "plmn"; /** @hide */ public static final String CA_CERT_ALIAS_DELIMITER = " "; private HashMap<String, String> mFields = new HashMap<String, String>(); private X509Certificate mCaCert; private X509Certificate[] mCaCerts; private PrivateKey mClientPrivateKey; private X509Certificate mClientCertificate; Loading Loading @@ -136,7 +147,7 @@ public class WifiEnterpriseConfig implements Parcelable { dest.writeString(entry.getValue()); } writeCertificate(dest, mCaCert); writeCertificates(dest, mCaCerts); if (mClientPrivateKey != null) { String algorithm = mClientPrivateKey.getAlgorithm(); Loading @@ -151,6 +162,17 @@ public class WifiEnterpriseConfig implements Parcelable { writeCertificate(dest, mClientCertificate); } 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 { Loading @@ -176,7 +198,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(); Loading @@ -199,6 +221,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(); Loading Loading @@ -398,6 +432,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. * Loading @@ -411,6 +475,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 Loading @@ -420,6 +513,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. * Loading @@ -431,31 +550,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. Loading