Loading api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -24696,6 +24696,7 @@ package android.net.wifi { method public java.security.cert.X509Certificate getCaCertificate(); method public java.security.cert.X509Certificate[] getCaCertificates(); method public java.security.cert.X509Certificate getClientCertificate(); method public java.security.cert.X509Certificate[] getClientCertificateChain(); method public java.lang.String getDomainSuffixMatch(); method public int getEapMethod(); method public java.lang.String getIdentity(); Loading @@ -24709,6 +24710,7 @@ package android.net.wifi { 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 setClientKeyEntryWithCertificateChain(java.security.PrivateKey, java.security.cert.X509Certificate[]); method public void setDomainSuffixMatch(java.lang.String); method public void setEapMethod(int); method public void setIdentity(java.lang.String); api/system-current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -27069,6 +27069,7 @@ package android.net.wifi { method public java.security.cert.X509Certificate getCaCertificate(); method public java.security.cert.X509Certificate[] getCaCertificates(); method public java.security.cert.X509Certificate getClientCertificate(); method public java.security.cert.X509Certificate[] getClientCertificateChain(); method public java.lang.String getDomainSuffixMatch(); method public int getEapMethod(); method public java.lang.String getIdentity(); Loading @@ -27082,6 +27083,7 @@ package android.net.wifi { 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 setClientKeyEntryWithCertificateChain(java.security.PrivateKey, java.security.cert.X509Certificate[]); method public void setDomainSuffixMatch(java.lang.String); method public void setEapMethod(int); method public void setIdentity(java.lang.String); api/test-current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -24770,6 +24770,7 @@ package android.net.wifi { method public java.security.cert.X509Certificate getCaCertificate(); method public java.security.cert.X509Certificate[] getCaCertificates(); method public java.security.cert.X509Certificate getClientCertificate(); method public java.security.cert.X509Certificate[] getClientCertificateChain(); method public java.lang.String getDomainSuffixMatch(); method public int getEapMethod(); method public java.lang.String getIdentity(); Loading @@ -24783,6 +24784,7 @@ package android.net.wifi { 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 setClientKeyEntryWithCertificateChain(java.security.PrivateKey, java.security.cert.X509Certificate[]); method public void setDomainSuffixMatch(java.lang.String); method public void setEapMethod(int); method public void setIdentity(java.lang.String); wifi/java/android/net/wifi/WifiEnterpriseConfig.java +79 −11 Original line number Diff line number Diff line Loading @@ -142,7 +142,7 @@ public class WifiEnterpriseConfig implements Parcelable { private HashMap<String, String> mFields = new HashMap<String, String>(); private X509Certificate[] mCaCerts; private PrivateKey mClientPrivateKey; private X509Certificate mClientCertificate; private X509Certificate[] mClientCertificateChain; private int mEapMethod = Eap.NONE; private int mPhase2Method = Phase2.NONE; Loading @@ -161,9 +161,19 @@ public class WifiEnterpriseConfig implements Parcelable { for (String key : source.mFields.keySet()) { mFields.put(key, source.mFields.get(key)); } mCaCerts = source.mCaCerts; if (source.mCaCerts != null) { mCaCerts = Arrays.copyOf(source.mCaCerts, source.mCaCerts.length); } else { mCaCerts = null; } mClientPrivateKey = source.mClientPrivateKey; mClientCertificate = source.mClientCertificate; if (source.mClientCertificateChain != null) { mClientCertificateChain = Arrays.copyOf( source.mClientCertificateChain, source.mClientCertificateChain.length); } else { mClientCertificateChain = null; } mEapMethod = source.mEapMethod; mPhase2Method = source.mPhase2Method; } Loading @@ -185,7 +195,7 @@ public class WifiEnterpriseConfig implements Parcelable { dest.writeInt(mPhase2Method); ParcelUtil.writeCertificates(dest, mCaCerts); ParcelUtil.writePrivateKey(dest, mClientPrivateKey); ParcelUtil.writeCertificate(dest, mClientCertificate); ParcelUtil.writeCertificates(dest, mClientCertificateChain); } public static final Creator<WifiEnterpriseConfig> CREATOR = Loading @@ -204,7 +214,7 @@ public class WifiEnterpriseConfig implements Parcelable { enterpriseConfig.mPhase2Method = in.readInt(); enterpriseConfig.mCaCerts = ParcelUtil.readCertificates(in); enterpriseConfig.mClientPrivateKey = ParcelUtil.readPrivateKey(in); enterpriseConfig.mClientCertificate = ParcelUtil.readCertificate(in); enterpriseConfig.mClientCertificateChain = ParcelUtil.readCertificates(in); return enterpriseConfig; } Loading Loading @@ -742,10 +752,51 @@ public class WifiEnterpriseConfig implements Parcelable { * @throws IllegalArgumentException for an invalid key or certificate. */ public void setClientKeyEntry(PrivateKey privateKey, X509Certificate clientCertificate) { if (clientCertificate != null) { if (clientCertificate.getBasicConstraints() != -1) { throw new IllegalArgumentException("Cannot be a CA certificate"); setClientKeyEntryWithCertificateChain(privateKey, new X509Certificate[] {clientCertificate}); } /** * Specify a private key and client certificate chain for client authorization. * * <p>A default name is automatically assigned to the key entry and used * with this configuration. The framework takes care of installing the * key entry when the config is saved and removing the key entry when * the config is removed. * @param privateKey * @param clientCertificateChain * @throws IllegalArgumentException for an invalid key or certificate. */ public void setClientKeyEntryWithCertificateChain(PrivateKey privateKey, X509Certificate[] clientCertificateChain) { X509Certificate[] newCerts = null; if (clientCertificateChain != null && clientCertificateChain.length > 0) { // We validate that this is a well formed chain that starts // with an end-certificate and is followed by CA certificates. // We don't validate that each following certificate verifies // the previous. https://en.wikipedia.org/wiki/Chain_of_trust // // Basic constraints is an X.509 extension type that defines // whether a given certificate is allowed to sign additional // certificates and what path length restrictions may exist. // We use this to judge whether the certificate is an end // certificate or a CA certificate. // https://cryptography.io/en/latest/x509/reference/ if (clientCertificateChain[0].getBasicConstraints() != -1) { throw new IllegalArgumentException( "First certificate in the chain must be a client end certificate"); } for (int i = 1; i < clientCertificateChain.length; i++) { if (clientCertificateChain[i].getBasicConstraints() == -1) { throw new IllegalArgumentException( "All certificates following the first must be CA certificates"); } } newCerts = Arrays.copyOf(clientCertificateChain, clientCertificateChain.length); if (privateKey == null) { throw new IllegalArgumentException("Client cert without a private key"); } Loading @@ -755,7 +806,7 @@ public class WifiEnterpriseConfig implements Parcelable { } mClientPrivateKey = privateKey; mClientCertificate = clientCertificate; mClientCertificateChain = newCerts; } /** Loading @@ -764,7 +815,24 @@ public class WifiEnterpriseConfig implements Parcelable { * @return X.509 client certificate */ public X509Certificate getClientCertificate() { return mClientCertificate; if (mClientCertificateChain != null && mClientCertificateChain.length > 0) { return mClientCertificateChain[0]; } else { return null; } } /** * Get the complete client certificate chain * * @return X.509 client certificates */ @Nullable public X509Certificate[] getClientCertificateChain() { if (mClientCertificateChain != null && mClientCertificateChain.length > 0) { return mClientCertificateChain; } else { return null; } } /** Loading @@ -772,7 +840,7 @@ public class WifiEnterpriseConfig implements Parcelable { */ public void resetClientKeyEntry() { mClientPrivateKey = null; mClientCertificate = null; mClientCertificateChain = null; } /** Loading wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java +36 −0 Original line number Diff line number Diff line Loading @@ -86,6 +86,42 @@ public class WifiEnterpriseConfigTest { assertTrue(result[0] == cert0 && result[1] == cert1); } @Test public void testSetClientCertificateChain() { PrivateKey clientKey = FakeKeys.RSA_KEY1; X509Certificate cert0 = FakeKeys.CLIENT_CERT; X509Certificate cert1 = FakeKeys.CA_CERT1; X509Certificate[] clientChain = new X509Certificate[] {cert0, cert1}; mEnterpriseConfig.setClientKeyEntryWithCertificateChain(clientKey, clientChain); X509Certificate[] result = mEnterpriseConfig.getClientCertificateChain(); assertEquals(result.length, 2); assertTrue(result[0] == cert0 && result[1] == cert1); assertTrue(mEnterpriseConfig.getClientCertificate() == cert0); } private boolean isClientCertificateChainInvalid(X509Certificate[] clientChain) { boolean exceptionThrown = false; try { PrivateKey clientKey = FakeKeys.RSA_KEY1; mEnterpriseConfig.setClientKeyEntryWithCertificateChain(clientKey, clientChain); } catch (IllegalArgumentException e) { exceptionThrown = true; } return exceptionThrown; } @Test public void testSetInvalidClientCertificateChain() { X509Certificate clientCert = FakeKeys.CLIENT_CERT; X509Certificate caCert = FakeKeys.CA_CERT1; assertTrue("Invalid client certificate", isClientCertificateChainInvalid(new X509Certificate[] {caCert, caCert})); assertTrue("Invalid CA certificate", isClientCertificateChainInvalid(new X509Certificate[] {clientCert, clientCert})); assertTrue("Both certificates invalid", isClientCertificateChainInvalid(new X509Certificate[] {caCert, clientCert})); } @Test public void testSaveSingleCaCertificateAlias() { final String alias = "single_alias 0"; Loading Loading
api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -24696,6 +24696,7 @@ package android.net.wifi { method public java.security.cert.X509Certificate getCaCertificate(); method public java.security.cert.X509Certificate[] getCaCertificates(); method public java.security.cert.X509Certificate getClientCertificate(); method public java.security.cert.X509Certificate[] getClientCertificateChain(); method public java.lang.String getDomainSuffixMatch(); method public int getEapMethod(); method public java.lang.String getIdentity(); Loading @@ -24709,6 +24710,7 @@ package android.net.wifi { 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 setClientKeyEntryWithCertificateChain(java.security.PrivateKey, java.security.cert.X509Certificate[]); method public void setDomainSuffixMatch(java.lang.String); method public void setEapMethod(int); method public void setIdentity(java.lang.String);
api/system-current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -27069,6 +27069,7 @@ package android.net.wifi { method public java.security.cert.X509Certificate getCaCertificate(); method public java.security.cert.X509Certificate[] getCaCertificates(); method public java.security.cert.X509Certificate getClientCertificate(); method public java.security.cert.X509Certificate[] getClientCertificateChain(); method public java.lang.String getDomainSuffixMatch(); method public int getEapMethod(); method public java.lang.String getIdentity(); Loading @@ -27082,6 +27083,7 @@ package android.net.wifi { 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 setClientKeyEntryWithCertificateChain(java.security.PrivateKey, java.security.cert.X509Certificate[]); method public void setDomainSuffixMatch(java.lang.String); method public void setEapMethod(int); method public void setIdentity(java.lang.String);
api/test-current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -24770,6 +24770,7 @@ package android.net.wifi { method public java.security.cert.X509Certificate getCaCertificate(); method public java.security.cert.X509Certificate[] getCaCertificates(); method public java.security.cert.X509Certificate getClientCertificate(); method public java.security.cert.X509Certificate[] getClientCertificateChain(); method public java.lang.String getDomainSuffixMatch(); method public int getEapMethod(); method public java.lang.String getIdentity(); Loading @@ -24783,6 +24784,7 @@ package android.net.wifi { 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 setClientKeyEntryWithCertificateChain(java.security.PrivateKey, java.security.cert.X509Certificate[]); method public void setDomainSuffixMatch(java.lang.String); method public void setEapMethod(int); method public void setIdentity(java.lang.String);
wifi/java/android/net/wifi/WifiEnterpriseConfig.java +79 −11 Original line number Diff line number Diff line Loading @@ -142,7 +142,7 @@ public class WifiEnterpriseConfig implements Parcelable { private HashMap<String, String> mFields = new HashMap<String, String>(); private X509Certificate[] mCaCerts; private PrivateKey mClientPrivateKey; private X509Certificate mClientCertificate; private X509Certificate[] mClientCertificateChain; private int mEapMethod = Eap.NONE; private int mPhase2Method = Phase2.NONE; Loading @@ -161,9 +161,19 @@ public class WifiEnterpriseConfig implements Parcelable { for (String key : source.mFields.keySet()) { mFields.put(key, source.mFields.get(key)); } mCaCerts = source.mCaCerts; if (source.mCaCerts != null) { mCaCerts = Arrays.copyOf(source.mCaCerts, source.mCaCerts.length); } else { mCaCerts = null; } mClientPrivateKey = source.mClientPrivateKey; mClientCertificate = source.mClientCertificate; if (source.mClientCertificateChain != null) { mClientCertificateChain = Arrays.copyOf( source.mClientCertificateChain, source.mClientCertificateChain.length); } else { mClientCertificateChain = null; } mEapMethod = source.mEapMethod; mPhase2Method = source.mPhase2Method; } Loading @@ -185,7 +195,7 @@ public class WifiEnterpriseConfig implements Parcelable { dest.writeInt(mPhase2Method); ParcelUtil.writeCertificates(dest, mCaCerts); ParcelUtil.writePrivateKey(dest, mClientPrivateKey); ParcelUtil.writeCertificate(dest, mClientCertificate); ParcelUtil.writeCertificates(dest, mClientCertificateChain); } public static final Creator<WifiEnterpriseConfig> CREATOR = Loading @@ -204,7 +214,7 @@ public class WifiEnterpriseConfig implements Parcelable { enterpriseConfig.mPhase2Method = in.readInt(); enterpriseConfig.mCaCerts = ParcelUtil.readCertificates(in); enterpriseConfig.mClientPrivateKey = ParcelUtil.readPrivateKey(in); enterpriseConfig.mClientCertificate = ParcelUtil.readCertificate(in); enterpriseConfig.mClientCertificateChain = ParcelUtil.readCertificates(in); return enterpriseConfig; } Loading Loading @@ -742,10 +752,51 @@ public class WifiEnterpriseConfig implements Parcelable { * @throws IllegalArgumentException for an invalid key or certificate. */ public void setClientKeyEntry(PrivateKey privateKey, X509Certificate clientCertificate) { if (clientCertificate != null) { if (clientCertificate.getBasicConstraints() != -1) { throw new IllegalArgumentException("Cannot be a CA certificate"); setClientKeyEntryWithCertificateChain(privateKey, new X509Certificate[] {clientCertificate}); } /** * Specify a private key and client certificate chain for client authorization. * * <p>A default name is automatically assigned to the key entry and used * with this configuration. The framework takes care of installing the * key entry when the config is saved and removing the key entry when * the config is removed. * @param privateKey * @param clientCertificateChain * @throws IllegalArgumentException for an invalid key or certificate. */ public void setClientKeyEntryWithCertificateChain(PrivateKey privateKey, X509Certificate[] clientCertificateChain) { X509Certificate[] newCerts = null; if (clientCertificateChain != null && clientCertificateChain.length > 0) { // We validate that this is a well formed chain that starts // with an end-certificate and is followed by CA certificates. // We don't validate that each following certificate verifies // the previous. https://en.wikipedia.org/wiki/Chain_of_trust // // Basic constraints is an X.509 extension type that defines // whether a given certificate is allowed to sign additional // certificates and what path length restrictions may exist. // We use this to judge whether the certificate is an end // certificate or a CA certificate. // https://cryptography.io/en/latest/x509/reference/ if (clientCertificateChain[0].getBasicConstraints() != -1) { throw new IllegalArgumentException( "First certificate in the chain must be a client end certificate"); } for (int i = 1; i < clientCertificateChain.length; i++) { if (clientCertificateChain[i].getBasicConstraints() == -1) { throw new IllegalArgumentException( "All certificates following the first must be CA certificates"); } } newCerts = Arrays.copyOf(clientCertificateChain, clientCertificateChain.length); if (privateKey == null) { throw new IllegalArgumentException("Client cert without a private key"); } Loading @@ -755,7 +806,7 @@ public class WifiEnterpriseConfig implements Parcelable { } mClientPrivateKey = privateKey; mClientCertificate = clientCertificate; mClientCertificateChain = newCerts; } /** Loading @@ -764,7 +815,24 @@ public class WifiEnterpriseConfig implements Parcelable { * @return X.509 client certificate */ public X509Certificate getClientCertificate() { return mClientCertificate; if (mClientCertificateChain != null && mClientCertificateChain.length > 0) { return mClientCertificateChain[0]; } else { return null; } } /** * Get the complete client certificate chain * * @return X.509 client certificates */ @Nullable public X509Certificate[] getClientCertificateChain() { if (mClientCertificateChain != null && mClientCertificateChain.length > 0) { return mClientCertificateChain; } else { return null; } } /** Loading @@ -772,7 +840,7 @@ public class WifiEnterpriseConfig implements Parcelable { */ public void resetClientKeyEntry() { mClientPrivateKey = null; mClientCertificate = null; mClientCertificateChain = null; } /** Loading
wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java +36 −0 Original line number Diff line number Diff line Loading @@ -86,6 +86,42 @@ public class WifiEnterpriseConfigTest { assertTrue(result[0] == cert0 && result[1] == cert1); } @Test public void testSetClientCertificateChain() { PrivateKey clientKey = FakeKeys.RSA_KEY1; X509Certificate cert0 = FakeKeys.CLIENT_CERT; X509Certificate cert1 = FakeKeys.CA_CERT1; X509Certificate[] clientChain = new X509Certificate[] {cert0, cert1}; mEnterpriseConfig.setClientKeyEntryWithCertificateChain(clientKey, clientChain); X509Certificate[] result = mEnterpriseConfig.getClientCertificateChain(); assertEquals(result.length, 2); assertTrue(result[0] == cert0 && result[1] == cert1); assertTrue(mEnterpriseConfig.getClientCertificate() == cert0); } private boolean isClientCertificateChainInvalid(X509Certificate[] clientChain) { boolean exceptionThrown = false; try { PrivateKey clientKey = FakeKeys.RSA_KEY1; mEnterpriseConfig.setClientKeyEntryWithCertificateChain(clientKey, clientChain); } catch (IllegalArgumentException e) { exceptionThrown = true; } return exceptionThrown; } @Test public void testSetInvalidClientCertificateChain() { X509Certificate clientCert = FakeKeys.CLIENT_CERT; X509Certificate caCert = FakeKeys.CA_CERT1; assertTrue("Invalid client certificate", isClientCertificateChainInvalid(new X509Certificate[] {caCert, caCert})); assertTrue("Invalid CA certificate", isClientCertificateChainInvalid(new X509Certificate[] {clientCert, clientCert})); assertTrue("Both certificates invalid", isClientCertificateChainInvalid(new X509Certificate[] {caCert, clientCert})); } @Test public void testSaveSingleCaCertificateAlias() { final String alias = "single_alias 0"; Loading