Add a client chain to WifiEnterpriseConfig
Add a list of supporting certificates to be presented in the process
of presenting client credentials.
Cherry-pick of e351176716
Bug: 34688653
Test: Compile, unit tests
Change-Id: I6afd8baf67312e8ddaaeefd26f30dacc51aa33bb
This commit is contained in:
@@ -24696,6 +24696,7 @@ package android.net.wifi {
|
|||||||
method public java.security.cert.X509Certificate getCaCertificate();
|
method public java.security.cert.X509Certificate getCaCertificate();
|
||||||
method public java.security.cert.X509Certificate[] getCaCertificates();
|
method public java.security.cert.X509Certificate[] getCaCertificates();
|
||||||
method public java.security.cert.X509Certificate getClientCertificate();
|
method public java.security.cert.X509Certificate getClientCertificate();
|
||||||
|
method public java.security.cert.X509Certificate[] getClientCertificateChain();
|
||||||
method public java.lang.String getDomainSuffixMatch();
|
method public java.lang.String getDomainSuffixMatch();
|
||||||
method public int getEapMethod();
|
method public int getEapMethod();
|
||||||
method public java.lang.String getIdentity();
|
method public java.lang.String getIdentity();
|
||||||
@@ -24709,6 +24710,7 @@ package android.net.wifi {
|
|||||||
method public void setCaCertificate(java.security.cert.X509Certificate);
|
method public void setCaCertificate(java.security.cert.X509Certificate);
|
||||||
method public void setCaCertificates(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 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 setDomainSuffixMatch(java.lang.String);
|
||||||
method public void setEapMethod(int);
|
method public void setEapMethod(int);
|
||||||
method public void setIdentity(java.lang.String);
|
method public void setIdentity(java.lang.String);
|
||||||
|
|||||||
@@ -27068,6 +27068,7 @@ package android.net.wifi {
|
|||||||
method public java.security.cert.X509Certificate getCaCertificate();
|
method public java.security.cert.X509Certificate getCaCertificate();
|
||||||
method public java.security.cert.X509Certificate[] getCaCertificates();
|
method public java.security.cert.X509Certificate[] getCaCertificates();
|
||||||
method public java.security.cert.X509Certificate getClientCertificate();
|
method public java.security.cert.X509Certificate getClientCertificate();
|
||||||
|
method public java.security.cert.X509Certificate[] getClientCertificateChain();
|
||||||
method public java.lang.String getDomainSuffixMatch();
|
method public java.lang.String getDomainSuffixMatch();
|
||||||
method public int getEapMethod();
|
method public int getEapMethod();
|
||||||
method public java.lang.String getIdentity();
|
method public java.lang.String getIdentity();
|
||||||
@@ -27081,6 +27082,7 @@ package android.net.wifi {
|
|||||||
method public void setCaCertificate(java.security.cert.X509Certificate);
|
method public void setCaCertificate(java.security.cert.X509Certificate);
|
||||||
method public void setCaCertificates(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 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 setDomainSuffixMatch(java.lang.String);
|
||||||
method public void setEapMethod(int);
|
method public void setEapMethod(int);
|
||||||
method public void setIdentity(java.lang.String);
|
method public void setIdentity(java.lang.String);
|
||||||
|
|||||||
@@ -24769,6 +24769,7 @@ package android.net.wifi {
|
|||||||
method public java.security.cert.X509Certificate getCaCertificate();
|
method public java.security.cert.X509Certificate getCaCertificate();
|
||||||
method public java.security.cert.X509Certificate[] getCaCertificates();
|
method public java.security.cert.X509Certificate[] getCaCertificates();
|
||||||
method public java.security.cert.X509Certificate getClientCertificate();
|
method public java.security.cert.X509Certificate getClientCertificate();
|
||||||
|
method public java.security.cert.X509Certificate[] getClientCertificateChain();
|
||||||
method public java.lang.String getDomainSuffixMatch();
|
method public java.lang.String getDomainSuffixMatch();
|
||||||
method public int getEapMethod();
|
method public int getEapMethod();
|
||||||
method public java.lang.String getIdentity();
|
method public java.lang.String getIdentity();
|
||||||
@@ -24782,6 +24783,7 @@ package android.net.wifi {
|
|||||||
method public void setCaCertificate(java.security.cert.X509Certificate);
|
method public void setCaCertificate(java.security.cert.X509Certificate);
|
||||||
method public void setCaCertificates(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 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 setDomainSuffixMatch(java.lang.String);
|
||||||
method public void setEapMethod(int);
|
method public void setEapMethod(int);
|
||||||
method public void setIdentity(java.lang.String);
|
method public void setIdentity(java.lang.String);
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ public class WifiEnterpriseConfig implements Parcelable {
|
|||||||
private HashMap<String, String> mFields = new HashMap<String, String>();
|
private HashMap<String, String> mFields = new HashMap<String, String>();
|
||||||
private X509Certificate[] mCaCerts;
|
private X509Certificate[] mCaCerts;
|
||||||
private PrivateKey mClientPrivateKey;
|
private PrivateKey mClientPrivateKey;
|
||||||
private X509Certificate mClientCertificate;
|
private X509Certificate[] mClientCertificateChain;
|
||||||
private int mEapMethod = Eap.NONE;
|
private int mEapMethod = Eap.NONE;
|
||||||
private int mPhase2Method = Phase2.NONE;
|
private int mPhase2Method = Phase2.NONE;
|
||||||
|
|
||||||
@@ -161,9 +161,19 @@ public class WifiEnterpriseConfig implements Parcelable {
|
|||||||
for (String key : source.mFields.keySet()) {
|
for (String key : source.mFields.keySet()) {
|
||||||
mFields.put(key, source.mFields.get(key));
|
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;
|
mClientPrivateKey = source.mClientPrivateKey;
|
||||||
mClientCertificate = source.mClientCertificate;
|
if (source.mClientCertificateChain != null) {
|
||||||
|
mClientCertificateChain = Arrays.copyOf(
|
||||||
|
source.mClientCertificateChain,
|
||||||
|
source.mClientCertificateChain.length);
|
||||||
|
} else {
|
||||||
|
mClientCertificateChain = null;
|
||||||
|
}
|
||||||
mEapMethod = source.mEapMethod;
|
mEapMethod = source.mEapMethod;
|
||||||
mPhase2Method = source.mPhase2Method;
|
mPhase2Method = source.mPhase2Method;
|
||||||
}
|
}
|
||||||
@@ -185,7 +195,7 @@ public class WifiEnterpriseConfig implements Parcelable {
|
|||||||
dest.writeInt(mPhase2Method);
|
dest.writeInt(mPhase2Method);
|
||||||
ParcelUtil.writeCertificates(dest, mCaCerts);
|
ParcelUtil.writeCertificates(dest, mCaCerts);
|
||||||
ParcelUtil.writePrivateKey(dest, mClientPrivateKey);
|
ParcelUtil.writePrivateKey(dest, mClientPrivateKey);
|
||||||
ParcelUtil.writeCertificate(dest, mClientCertificate);
|
ParcelUtil.writeCertificates(dest, mClientCertificateChain);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Creator<WifiEnterpriseConfig> CREATOR =
|
public static final Creator<WifiEnterpriseConfig> CREATOR =
|
||||||
@@ -204,7 +214,7 @@ public class WifiEnterpriseConfig implements Parcelable {
|
|||||||
enterpriseConfig.mPhase2Method = in.readInt();
|
enterpriseConfig.mPhase2Method = in.readInt();
|
||||||
enterpriseConfig.mCaCerts = ParcelUtil.readCertificates(in);
|
enterpriseConfig.mCaCerts = ParcelUtil.readCertificates(in);
|
||||||
enterpriseConfig.mClientPrivateKey = ParcelUtil.readPrivateKey(in);
|
enterpriseConfig.mClientPrivateKey = ParcelUtil.readPrivateKey(in);
|
||||||
enterpriseConfig.mClientCertificate = ParcelUtil.readCertificate(in);
|
enterpriseConfig.mClientCertificateChain = ParcelUtil.readCertificates(in);
|
||||||
return enterpriseConfig;
|
return enterpriseConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -742,10 +752,51 @@ public class WifiEnterpriseConfig implements Parcelable {
|
|||||||
* @throws IllegalArgumentException for an invalid key or certificate.
|
* @throws IllegalArgumentException for an invalid key or certificate.
|
||||||
*/
|
*/
|
||||||
public void setClientKeyEntry(PrivateKey privateKey, X509Certificate clientCertificate) {
|
public void setClientKeyEntry(PrivateKey privateKey, X509Certificate clientCertificate) {
|
||||||
if (clientCertificate != null) {
|
setClientKeyEntryWithCertificateChain(privateKey,
|
||||||
if (clientCertificate.getBasicConstraints() != -1) {
|
new X509Certificate[] {clientCertificate});
|
||||||
throw new IllegalArgumentException("Cannot be a CA certificate");
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
if (privateKey == null) {
|
||||||
throw new IllegalArgumentException("Client cert without a private key");
|
throw new IllegalArgumentException("Client cert without a private key");
|
||||||
}
|
}
|
||||||
@@ -755,7 +806,7 @@ public class WifiEnterpriseConfig implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mClientPrivateKey = privateKey;
|
mClientPrivateKey = privateKey;
|
||||||
mClientCertificate = clientCertificate;
|
mClientCertificateChain = newCerts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -764,7 +815,24 @@ public class WifiEnterpriseConfig implements Parcelable {
|
|||||||
* @return X.509 client certificate
|
* @return X.509 client certificate
|
||||||
*/
|
*/
|
||||||
public X509Certificate getClientCertificate() {
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -772,7 +840,7 @@ public class WifiEnterpriseConfig implements Parcelable {
|
|||||||
*/
|
*/
|
||||||
public void resetClientKeyEntry() {
|
public void resetClientKeyEntry() {
|
||||||
mClientPrivateKey = null;
|
mClientPrivateKey = null;
|
||||||
mClientCertificate = null;
|
mClientCertificateChain = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -86,6 +86,42 @@ public class WifiEnterpriseConfigTest {
|
|||||||
assertTrue(result[0] == cert0 && result[1] == cert1);
|
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
|
@Test
|
||||||
public void testSaveSingleCaCertificateAlias() {
|
public void testSaveSingleCaCertificateAlias() {
|
||||||
final String alias = "single_alias 0";
|
final String alias = "single_alias 0";
|
||||||
|
|||||||
Reference in New Issue
Block a user