blob: 3e692c36fb30fd125027daf04031595ecc78a3c3 [file] [log] [blame]
/*
* Copyright (C) 2014 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.cts.deviceowner;
import android.net.http.X509TrustManagerExtensions;
import android.security.NetworkSecurityPolicy;
import java.io.ByteArrayInputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.List;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import static com.android.cts.deviceowner.FakeKeys.FAKE_DSA_1;
import static com.android.cts.deviceowner.FakeKeys.FAKE_RSA_1;
public class CaCertManagementTest extends BaseDeviceOwnerTest {
/**
* Test: device admins should be able to list all installed certs.
*
* <p>The list of certificates must never be {@code null}.
*/
public void testCanRetrieveListOfInstalledCaCerts() {
List<byte[]> caCerts = mDevicePolicyManager.getInstalledCaCerts(getWho());
assertNotNull(caCerts);
}
/**
* Test: a valid cert should be installable and also removable.
*/
public void testCanInstallAndUninstallACaCert()
throws CertificateException, GeneralSecurityException {
assertUninstalled(FAKE_RSA_1.caCertificate);
assertUninstalled(FAKE_DSA_1.caCertificate);
assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_RSA_1.caCertificate));
assertInstalled(FAKE_RSA_1.caCertificate);
assertUninstalled(FAKE_DSA_1.caCertificate);
mDevicePolicyManager.uninstallCaCert(getWho(), FAKE_RSA_1.caCertificate);
assertUninstalled(FAKE_RSA_1.caCertificate);
assertUninstalled(FAKE_DSA_1.caCertificate);
}
/**
* Test: removing one certificate must not remove any others.
*/
public void testUninstallationIsSelective()
throws CertificateException, GeneralSecurityException {
assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_RSA_1.caCertificate));
assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_DSA_1.caCertificate));
mDevicePolicyManager.uninstallCaCert(getWho(), FAKE_DSA_1.caCertificate);
assertInstalled(FAKE_RSA_1.caCertificate);
assertUninstalled(FAKE_DSA_1.caCertificate);
mDevicePolicyManager.uninstallCaCert(getWho(), FAKE_RSA_1.caCertificate);
}
/**
* Test: uninstallAllUserCaCerts should be equivalent to calling uninstallCaCert on every
* supplementary installed certificate.
*/
public void testCanUninstallAllUserCaCerts()
throws CertificateException, GeneralSecurityException {
assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_RSA_1.caCertificate));
assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_DSA_1.caCertificate));
mDevicePolicyManager.uninstallAllUserCaCerts(getWho());
assertUninstalled(FAKE_RSA_1.caCertificate);
assertUninstalled(FAKE_DSA_1.caCertificate);
}
private void assertInstalled(byte[] caBytes)
throws CertificateException, GeneralSecurityException {
Certificate caCert = readCertificate(caBytes);
assertTrue(isCaCertInstalledAndTrusted(caCert));
}
private void assertUninstalled(byte[] caBytes)
throws CertificateException, GeneralSecurityException {
Certificate caCert = readCertificate(caBytes);
assertFalse(isCaCertInstalledAndTrusted(caCert));
}
private static X509TrustManager getFirstX509TrustManager(TrustManagerFactory tmf) {
for (TrustManager trustManager : tmf.getTrustManagers()) {
if (trustManager instanceof X509TrustManager) {
return (X509TrustManager) trustManager;
}
}
throw new RuntimeException("Unable to find X509TrustManager");
}
/**
* Whether a given cert, or one a lot like it, has been installed system-wide and is available
* to all apps.
*
* <p>A CA certificate is "installed" if it matches all of the following conditions:
* <ul>
* <li>{@link DevicePolicyManager#hasCaCertInstalled} returns {@code true}.</li>
* <li>{@link DevicePolicyManager#getInstalledCaCerts} lists a matching certificate (not
* necessarily exactly the same) in its response.</li>
* <li>Any new instances of {@link TrustManager} should report the certificate among their
* accepted issuer list -- older instances may keep the set of issuers they were created
* with until explicitly refreshed.</li>
*
* @return {@code true} if installed by all metrics, {@code false} if not installed by any
* metric. In any other case an {@link AssertionError} will be thrown.
*/
private boolean isCaCertInstalledAndTrusted(Certificate caCert)
throws GeneralSecurityException, CertificateException {
boolean installed = mDevicePolicyManager.hasCaCertInstalled(getWho(), caCert.getEncoded());
boolean listed = false;
for (byte[] certBuffer : mDevicePolicyManager.getInstalledCaCerts(getWho())) {
if (caCert.equals(readCertificate(certBuffer))) {
listed = true;
}
}
NetworkSecurityPolicy.getInstance().handleTrustStorageUpdate();
// Verify that the user added CA is reflected in the default X509TrustManager.
final TrustManagerFactory tmf =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
// Use platform provided CA store.
tmf.init((KeyStore) null);
X509TrustManager tm = getFirstX509TrustManager(tmf);
boolean trusted = Arrays.asList(tm.getAcceptedIssuers()).contains(caCert);
X509TrustManagerExtensions xtm = new X509TrustManagerExtensions(tm);
boolean userAddedCertificate = xtm.isUserAddedCertificate((X509Certificate) caCert);
// All three responses should match - if an installed certificate isn't trusted or (worse)
// a trusted certificate isn't even installed we should
assertEquals(installed, listed);
assertEquals(installed, trusted);
assertEquals(installed, userAddedCertificate);
return installed;
}
/**
* Convert an encoded certificate back into a {@link Certificate}.
*
* Instantiates a fresh CertificateFactory every time for repeatability.
*/
private static Certificate readCertificate(byte[] certBuffer) throws CertificateException {
final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
return certFactory.generateCertificate(new ByteArrayInputStream(certBuffer));
}
}