diff options
author | Peter Qiu <zqiu@google.com> | 2017-03-20 14:55:45 -0700 |
---|---|---|
committer | Peter Qiu <zqiu@google.com> | 2017-03-29 10:32:25 -0700 |
commit | f331a6bf511cc9d105a45219548d0ad3feab5a70 (patch) | |
tree | 8bf3b5aeba076a408607271645ee88bbf525442d /service | |
parent | bb2fdf553e6580923e1dc3e6ac90ca777c5d7226 (diff) |
hotspot2: verify CA certificate before installing Passpoint provider
For Hotspot 2.0 Release 1, the provisioning method is not standardized,
so to improve security, the CA certificate must be trusted by one
of the pre-loaded public CAs in the system key store.
So verify the CA certificate if one is provided before installing
the Passpoint provider.
A utility class CertificateVerifier is created in order to easily mock
the certificate verification in unit tests.
Bug: 34460350
Test: manual test
Change-Id: I627ef9da2876ffbaf29aadb2d5b281c75ec1d145
Diffstat (limited to 'service')
3 files changed, 83 insertions, 0 deletions
diff --git a/service/java/com/android/server/wifi/hotspot2/CertificateVerifier.java b/service/java/com/android/server/wifi/hotspot2/CertificateVerifier.java new file mode 100644 index 000000000..004a32fbd --- /dev/null +++ b/service/java/com/android/server/wifi/hotspot2/CertificateVerifier.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wifi.hotspot2; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.cert.CertPath; +import java.security.cert.CertPathValidator; +import java.security.cert.CertificateFactory; +import java.security.cert.PKIXParameters; +import java.security.cert.X509Certificate; +import java.util.Arrays; + +/** + * Utility class used for verifying certificates against the pre-loaded public CAs in the + * system key store. This class is created to allow the certificate verification to be mocked in + * unit tests. + */ +public class CertificateVerifier { + + /** + * Verify that the given certificate is trusted by one of the pre-loaded public CAs in the + * system key store. + * + * @param caCert The CA Certificate to verify + * @throws GeneralSecurityException + * @throws IOException + */ + public void verifyCaCert(X509Certificate caCert) + throws GeneralSecurityException, IOException { + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + CertPathValidator validator = + CertPathValidator.getInstance(CertPathValidator.getDefaultType()); + CertPath path = factory.generateCertPath( + Arrays.asList(caCert)); + KeyStore ks = KeyStore.getInstance("AndroidCAStore"); + ks.load(null, null); + PKIXParameters params = new PKIXParameters(ks); + params.setRevocationEnabled(false); + validator.validate(path, params); + } +} diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java index f472d86db..51781de27 100644 --- a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java +++ b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java @@ -93,6 +93,7 @@ public class PasspointManager { private final AnqpCache mAnqpCache; private final ANQPRequestManager mAnqpRequestManager; private final WifiConfigManager mWifiConfigManager; + private final CertificateVerifier mCertVerifier; // Counter used for assigning unique identifier to each provider. private long mProviderIndex; @@ -199,6 +200,7 @@ public class PasspointManager { mProviders = new HashMap<>(); mAnqpCache = objectFactory.makeAnqpCache(clock); mAnqpRequestManager = objectFactory.makeANQPRequestManager(mHandler, clock); + mCertVerifier = objectFactory.makeCertificateVerifier(); mWifiConfigManager = wifiConfigManager; mProviderIndex = 0; wifiConfigStore.registerStoreData(objectFactory.makePasspointConfigStoreData( @@ -226,6 +228,21 @@ public class PasspointManager { return false; } + // For Hotspot 2.0 Release 1, the CA Certificate must be trusted by one of the pre-loaded + // public CAs in the system key store on the device. Since the provisioning method + // for Release 1 is not standardized nor trusted, this is a reasonable restriction + // to improve security. The presence of UpdateIdentifier is used to differentiate + // between R1 and R2 configuration. + if (config.getUpdateIdentifier() == Integer.MIN_VALUE + && config.getCredential().getCaCertificate() != null) { + try { + mCertVerifier.verifyCaCert(config.getCredential().getCaCertificate()); + } catch (Exception e) { + Log.e(TAG, "Failed to verify CA certificate: " + e.getMessage()); + return false; + } + } + // Create a provider and install the necessary certificates and keys. PasspointProvider newProvider = mObjectFactory.makePasspointProvider( config, mKeyStore, mSimAccessor, mProviderIndex++); diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointObjectFactory.java b/service/java/com/android/server/wifi/hotspot2/PasspointObjectFactory.java index 821cee67a..16982969b 100644 --- a/service/java/com/android/server/wifi/hotspot2/PasspointObjectFactory.java +++ b/service/java/com/android/server/wifi/hotspot2/PasspointObjectFactory.java @@ -86,4 +86,13 @@ public class PasspointObjectFactory{ public ANQPRequestManager makeANQPRequestManager(PasspointEventHandler handler, Clock clock) { return new ANQPRequestManager(handler, clock); } + + /** + * Create an instance of {@link CertificateVerifier}. + * + * @return {@link CertificateVerifier} + */ + public CertificateVerifier makeCertificateVerifier() { + return new CertificateVerifier(); + } } |