summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHai Shalom <haishalom@google.com>2020-08-05 00:22:47 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2020-08-05 00:22:47 +0000
commitc83a6ec1e99253a78d843237c0757df16f9b4f7d (patch)
treed67fd821fe8302d723a2c292f547964ab39728d1
parent296f72cc1951e2af64fbdd0522f68237353f4d61 (diff)
parentc47516c563f23da2a1c0785b3959b33f77340d31 (diff)
Merge "[WPA3-Enterprise] Improve the security and robustness of profiles" into rvc-qpr-dev
-rw-r--r--service/java/com/android/server/wifi/WifiKeyStore.java129
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiKeyStoreTest.java120
2 files changed, 214 insertions, 35 deletions
diff --git a/service/java/com/android/server/wifi/WifiKeyStore.java b/service/java/com/android/server/wifi/WifiKeyStore.java
index 70daa0d55..c248d2269 100644
--- a/service/java/com/android/server/wifi/WifiKeyStore.java
+++ b/service/java/com/android/server/wifi/WifiKeyStore.java
@@ -30,6 +30,7 @@ import com.android.server.wifi.util.ArrayUtils;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
+import java.security.Principal;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
@@ -276,52 +277,110 @@ public class WifiKeyStore {
// For WPA3-Enterprise 192-bit networks, set the SuiteBCipher field based on the
// CA certificate type. Suite-B requires SHA384, reject other certs.
if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SUITE_B_192)) {
- // Read the first CA certificate, and initialize
- Certificate caCert = null;
+ // Read the CA certificates, and initialize
+ String[] caAliases = config.enterpriseConfig.getCaCertificateAliases();
+
+ if (caAliases == null || caAliases.length == 0) {
+ Log.e(TAG, "No CA aliases in profile");
+ return false;
+ }
+
+ int caCertType = -1;
+ int prevCaCertType = -1;
+ for (String caAlias : caAliases) {
+ Certificate caCert = null;
+ try {
+ caCert = mKeyStore.getCertificate(caAlias);
+ } catch (KeyStoreException e) {
+ Log.e(TAG, "Failed to get Suite-B certificate", e);
+ }
+ if (caCert == null || !(caCert instanceof X509Certificate)) {
+ Log.e(TAG, "Failed reading CA certificate for Suite-B");
+ return false;
+ }
+
+ // Confirm that the CA certificate is compatible with Suite-B requirements
+ caCertType = getSuiteBCipherFromCert((X509Certificate) caCert);
+ if (caCertType < 0) {
+ return false;
+ }
+ if (prevCaCertType != -1) {
+ if (prevCaCertType != caCertType) {
+ Log.e(TAG, "Incompatible CA certificates");
+ return false;
+ }
+ }
+ prevCaCertType = caCertType;
+ }
+
+ Certificate clientCert = null;
try {
- caCert = mKeyStore.getCertificate(config.enterpriseConfig.getCaCertificateAlias());
+ clientCert = mKeyStore.getCertificate(config.enterpriseConfig
+ .getClientCertificateAlias());
} catch (KeyStoreException e) {
- Log.e(TAG, "Failed to get Suite-B certificate", e);
+ Log.e(TAG, "Failed to get Suite-B client certificate", e);
}
- if (caCert == null || !(caCert instanceof X509Certificate)) {
- Log.e(TAG, "Failed reading CA certificate for Suite-B");
+ if (clientCert == null || !(clientCert instanceof X509Certificate)) {
+ Log.e(TAG, "Failed reading client certificate for Suite-B");
return false;
}
- X509Certificate x509CaCert = (X509Certificate) caCert;
- String sigAlgOid = x509CaCert.getSigAlgOID();
- if (mVerboseLoggingEnabled) {
- Log.d(TAG, "Signature algorithm: " + sigAlgOid);
+
+ int clientCertType = getSuiteBCipherFromCert((X509Certificate) clientCert);
+ if (clientCertType < 0) {
+ return false;
}
- config.allowedSuiteBCiphers.clear();
- // Wi-Fi alliance requires the use of both ECDSA secp384r1 and RSA 3072 certificates
- // in WPA3-Enterprise 192-bit security networks, which are also known as Suite-B-192
- // networks, even though NSA Suite-B-192 mandates ECDSA only. The use of the term
- // Suite-B was already coined in the IEEE 802.11-2016 specification for
- // AKM 00-0F-AC but the test plan for WPA3-Enterprise 192-bit for APs mandates
- // support for both RSA and ECDSA, and for STAs it mandates ECDSA and optionally
- // RSA. In order to be compatible with all WPA3-Enterprise 192-bit deployments,
- // we are supporting both types here.
- if (sigAlgOid.equals("1.2.840.113549.1.1.12")) {
- // sha384WithRSAEncryption
- config.allowedSuiteBCiphers.set(
- WifiConfiguration.SuiteBCipher.ECDHE_RSA);
- if (mVerboseLoggingEnabled) {
- Log.d(TAG, "Selecting Suite-B RSA");
- }
- } else if (sigAlgOid.equals("1.2.840.10045.4.3.3")) {
- // ecdsa-with-SHA384
- config.allowedSuiteBCiphers.set(
- WifiConfiguration.SuiteBCipher.ECDHE_ECDSA);
- if (mVerboseLoggingEnabled) {
- Log.d(TAG, "Selecting Suite-B ECDSA");
- }
+ if (clientCertType == caCertType) {
+ config.allowedSuiteBCiphers.clear();
+ config.allowedSuiteBCiphers.set(clientCertType);
} else {
- Log.e(TAG, "Invalid CA certificate type for Suite-B: "
- + sigAlgOid);
+ Log.e(TAG, "Client certificate for Suite-B is incompatible with the CA "
+ + "certificate");
return false;
}
}
return true;
}
+
+ /**
+ * Get the Suite-B cipher from the certificate
+ *
+ * @param x509Certificate Certificate to process
+ * @return WifiConfiguration.SuiteBCipher.ECDHE_RSA if the certificate OID matches the Suite-B
+ * requirements for RSA certificates, WifiConfiguration.SuiteBCipher.ECDHE_ECDSA if the
+ * certificate OID matches the Suite-B requirements for ECDSA certificates, or -1 otherwise.
+ */
+ private int getSuiteBCipherFromCert(X509Certificate x509Certificate) {
+ String sigAlgOid = x509Certificate.getSigAlgOID();
+ if (mVerboseLoggingEnabled) {
+ Principal p = x509Certificate.getSubjectX500Principal();
+ if (p != null && !TextUtils.isEmpty(p.getName())) {
+ Log.d(TAG, "Checking cert " + p.getName());
+ }
+ }
+
+ // Wi-Fi alliance requires the use of both ECDSA secp384r1 and RSA 3072 certificates
+ // in WPA3-Enterprise 192-bit security networks, which are also known as Suite-B-192
+ // networks, even though NSA Suite-B-192 mandates ECDSA only. The use of the term
+ // Suite-B was already coined in the IEEE 802.11-2016 specification for
+ // AKM 00-0F-AC but the test plan for WPA3-Enterprise 192-bit for APs mandates
+ // support for both RSA and ECDSA, and for STAs it mandates ECDSA and optionally
+ // RSA. In order to be compatible with all WPA3-Enterprise 192-bit deployments,
+ // we are supporting both types here.
+ if (sigAlgOid.equals("1.2.840.113549.1.1.12")) {
+ // sha384WithRSAEncryption
+ if (mVerboseLoggingEnabled) {
+ Log.d(TAG, "Found Suite-B RSA certificate");
+ }
+ return WifiConfiguration.SuiteBCipher.ECDHE_RSA;
+ } else if (sigAlgOid.equals("1.2.840.10045.4.3.3")) {
+ // ecdsa-with-SHA384
+ if (mVerboseLoggingEnabled) {
+ Log.d(TAG, "Found Suite-B ECDSA certificate");
+ }
+ return WifiConfiguration.SuiteBCipher.ECDHE_ECDSA;
+ }
+ Log.e(TAG, "Invalid certificate type for Suite-B: " + sigAlgOid);
+ return -1;
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiKeyStoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiKeyStoreTest.java
index 8eef7e7d0..f6cae66db 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiKeyStoreTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiKeyStoreTest.java
@@ -16,6 +16,7 @@
package com.android.server.wifi;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.AdditionalMatchers.aryEq;
@@ -223,6 +224,8 @@ public class WifiKeyStoreTest extends WifiBaseTest {
*/
@Test
public void testConfigureSuiteBRsa3072() throws Exception {
+ when(mWifiEnterpriseConfig.getCaCertificateAliases())
+ .thenReturn(new String[]{USER_CA_CERT_ALIAS});
when(mWifiEnterpriseConfig.getClientPrivateKey())
.thenReturn(FakeKeys.CLIENT_SUITE_B_RSA3072_KEY);
when(mWifiEnterpriseConfig.getClientCertificate()).thenReturn(
@@ -249,6 +252,8 @@ public class WifiKeyStoreTest extends WifiBaseTest {
*/
@Test
public void testConfigureSuiteBEcdsa() throws Exception {
+ when(mWifiEnterpriseConfig.getCaCertificateAliases())
+ .thenReturn(new String[]{USER_CA_CERT_ALIAS});
when(mWifiEnterpriseConfig.getClientPrivateKey())
.thenReturn(FakeKeys.CLIENT_SUITE_B_ECC_KEY);
when(mWifiEnterpriseConfig.getClientCertificate()).thenReturn(
@@ -269,4 +274,119 @@ public class WifiKeyStoreTest extends WifiBaseTest {
assertTrue(
savedNetwork.allowedSuiteBCiphers.get(WifiConfiguration.SuiteBCipher.ECDHE_ECDSA));
}
+
+ /**
+ * Test configuring WPA3-Enterprise in 192-bit mode for RSA 3072 fails when CA and client
+ * certificates are not of the same type.
+ */
+ @Test
+ public void testConfigurationFailureSuiteB() throws Exception {
+ // Create a configuration with RSA client cert and ECDSA CA cert
+ when(mWifiEnterpriseConfig.getClientPrivateKey())
+ .thenReturn(FakeKeys.CLIENT_SUITE_B_RSA3072_KEY);
+ when(mWifiEnterpriseConfig.getClientCertificate()).thenReturn(
+ FakeKeys.CLIENT_SUITE_B_RSA3072_CERT);
+ when(mWifiEnterpriseConfig.getCaCertificate()).thenReturn(FakeKeys.CA_SUITE_B_ECDSA_CERT);
+ when(mWifiEnterpriseConfig.getClientCertificateChain())
+ .thenReturn(new X509Certificate[]{FakeKeys.CLIENT_SUITE_B_RSA3072_CERT});
+ when(mWifiEnterpriseConfig.getCaCertificates())
+ .thenReturn(new X509Certificate[]{FakeKeys.CA_SUITE_B_ECDSA_CERT});
+ when(mKeyStore.getCertificate(eq(USER_CERT_ALIAS))).thenReturn(
+ FakeKeys.CLIENT_SUITE_B_RSA3072_CERT);
+ when(mKeyStore.getCertificate(eq(USER_CA_CERT_ALIASES[0]))).thenReturn(
+ FakeKeys.CA_SUITE_B_ECDSA_CERT);
+ WifiConfiguration savedNetwork = WifiConfigurationTestUtil.createEapSuiteBNetwork(
+ WifiConfiguration.SuiteBCipher.ECDHE_ECDSA);
+ savedNetwork.enterpriseConfig = mWifiEnterpriseConfig;
+ assertFalse(mWifiKeyStore.updateNetworkKeys(savedNetwork, null));
+ }
+
+ /**
+ * Test configuring WPA3-Enterprise in 192-bit mode for RSA 3072 fails when CA is RSA but not
+ * with the required security
+ */
+ @Test
+ public void testConfigurationFailureSuiteBNon3072Rsa() throws Exception {
+ // Create a configuration with RSA client cert and weak RSA CA cert
+ when(mWifiEnterpriseConfig.getClientPrivateKey())
+ .thenReturn(FakeKeys.CLIENT_SUITE_B_RSA3072_KEY);
+ when(mWifiEnterpriseConfig.getClientCertificate()).thenReturn(
+ FakeKeys.CLIENT_SUITE_B_RSA3072_CERT);
+ when(mWifiEnterpriseConfig.getCaCertificate()).thenReturn(FakeKeys.CA_CERT0);
+ when(mWifiEnterpriseConfig.getClientCertificateChain())
+ .thenReturn(new X509Certificate[]{FakeKeys.CLIENT_SUITE_B_RSA3072_CERT});
+ when(mWifiEnterpriseConfig.getCaCertificates())
+ .thenReturn(new X509Certificate[]{FakeKeys.CA_CERT0});
+ when(mKeyStore.getCertificate(eq(USER_CERT_ALIAS))).thenReturn(
+ FakeKeys.CLIENT_SUITE_B_RSA3072_CERT);
+ when(mKeyStore.getCertificate(eq(USER_CA_CERT_ALIASES[0]))).thenReturn(
+ FakeKeys.CA_CERT0);
+ WifiConfiguration savedNetwork = WifiConfigurationTestUtil.createEapSuiteBNetwork(
+ WifiConfiguration.SuiteBCipher.ECDHE_RSA);
+ savedNetwork.enterpriseConfig = mWifiEnterpriseConfig;
+ assertFalse(mWifiKeyStore.updateNetworkKeys(savedNetwork, null));
+ }
+
+ /**
+ * Test configuring WPA3-Enterprise in 192-bit mode for RSA 3072 fails when one CA in the list
+ * is RSA but not with the required security
+ */
+ @Test
+ public void testConfigurationFailureSuiteBNon3072RsaInList() throws Exception {
+ // Create a configuration with RSA client cert and weak RSA CA cert
+ when(mWifiEnterpriseConfig.getClientPrivateKey())
+ .thenReturn(FakeKeys.CLIENT_SUITE_B_RSA3072_KEY);
+ when(mWifiEnterpriseConfig.getClientCertificate()).thenReturn(
+ FakeKeys.CLIENT_SUITE_B_RSA3072_CERT);
+ when(mWifiEnterpriseConfig.getCaCertificate()).thenReturn(FakeKeys.CA_SUITE_B_RSA3072_CERT);
+ when(mWifiEnterpriseConfig.getClientCertificateChain())
+ .thenReturn(new X509Certificate[]{FakeKeys.CLIENT_SUITE_B_RSA3072_CERT});
+ when(mWifiEnterpriseConfig.getCaCertificates())
+ .thenReturn(
+ new X509Certificate[]{FakeKeys.CA_SUITE_B_RSA3072_CERT, FakeKeys.CA_CERT0});
+ when(mKeyStore.getCertificate(eq(USER_CERT_ALIAS))).thenReturn(
+ FakeKeys.CLIENT_SUITE_B_RSA3072_CERT);
+ when(mKeyStore.getCertificate(eq(USER_CA_CERT_ALIASES[0]))).thenReturn(
+ FakeKeys.CA_SUITE_B_RSA3072_CERT);
+ when(mKeyStore.getCertificate(eq(USER_CA_CERT_ALIASES[1]))).thenReturn(
+ FakeKeys.CA_CERT0);
+ when(mWifiEnterpriseConfig.getCaCertificateAliases())
+ .thenReturn(USER_CA_CERT_ALIASES);
+ WifiConfiguration savedNetwork = WifiConfigurationTestUtil.createEapSuiteBNetwork(
+ WifiConfiguration.SuiteBCipher.ECDHE_RSA);
+ savedNetwork.enterpriseConfig = mWifiEnterpriseConfig;
+ assertFalse(mWifiKeyStore.updateNetworkKeys(savedNetwork, null));
+ }
+
+ /**
+ * Test configuring WPA3-Enterprise in 192-bit mode for RSA 3072 fails when one CA in the list
+ * is RSA and the other is ECDSA
+ */
+ @Test
+ public void testConfigurationFailureSuiteBRsaAndEcdsaInList() throws Exception {
+ // Create a configuration with RSA client cert and weak RSA CA cert
+ when(mWifiEnterpriseConfig.getClientPrivateKey())
+ .thenReturn(FakeKeys.CLIENT_SUITE_B_RSA3072_KEY);
+ when(mWifiEnterpriseConfig.getClientCertificate()).thenReturn(
+ FakeKeys.CLIENT_SUITE_B_RSA3072_CERT);
+ when(mWifiEnterpriseConfig.getCaCertificate()).thenReturn(FakeKeys.CA_SUITE_B_RSA3072_CERT);
+ when(mWifiEnterpriseConfig.getClientCertificateChain())
+ .thenReturn(new X509Certificate[]{FakeKeys.CLIENT_SUITE_B_RSA3072_CERT});
+ when(mWifiEnterpriseConfig.getCaCertificates())
+ .thenReturn(
+ new X509Certificate[]{FakeKeys.CA_SUITE_B_RSA3072_CERT,
+ FakeKeys.CA_SUITE_B_ECDSA_CERT});
+ when(mKeyStore.getCertificate(eq(USER_CERT_ALIAS))).thenReturn(
+ FakeKeys.CLIENT_SUITE_B_RSA3072_CERT);
+ when(mKeyStore.getCertificate(eq(USER_CA_CERT_ALIASES[0]))).thenReturn(
+ FakeKeys.CA_SUITE_B_RSA3072_CERT);
+ when(mKeyStore.getCertificate(eq(USER_CA_CERT_ALIASES[1]))).thenReturn(
+ FakeKeys.CA_SUITE_B_ECDSA_CERT);
+ when(mWifiEnterpriseConfig.getCaCertificateAliases())
+ .thenReturn(USER_CA_CERT_ALIASES);
+ WifiConfiguration savedNetwork = WifiConfigurationTestUtil.createEapSuiteBNetwork(
+ WifiConfiguration.SuiteBCipher.ECDHE_RSA);
+ savedNetwork.enterpriseConfig = mWifiEnterpriseConfig;
+ assertFalse(mWifiKeyStore.updateNetworkKeys(savedNetwork, null));
+ }
}