summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHai Shalom <haishalom@google.com>2020-07-22 17:13:55 -0700
committerHai Shalom <haishalom@google.com>2020-07-28 21:59:12 +0000
commitc47516c563f23da2a1c0785b3959b33f77340d31 (patch)
tree84c886c4c88007dfd0feee60b013bf08fc16da08
parent9b3fb0d1c18c2559c1ad5a7be9de3ad5ce3c12c9 (diff)
[WPA3-Enterprise] Improve the security and robustness of profiles
Updated the logic with more robust checks that enforce checks on all CA certificates in the list and on the user certificate as well. Bug: 161939357 Test: atest WifiKeyStoreTest Test: Connect to WPA3-Enterprise 192-bit ECDSA and RSA networks Test: Connect to WPA2-Enterprise network Change-Id: I8e6becb66f245ee36a9b4e62569784f567412a33 Merged-In: I8e6becb66f245ee36a9b4e62569784f567412a33 (cherry picked from commit 555ee293678a085f6240156eb1728709dd7bd73e)
-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));
+ }
}