Merge "Require actual certificates for testNoAddedCertificates."
diff --git a/tests/tests/security/src/android/security/cts/CertificateTest.java b/tests/tests/security/src/android/security/cts/CertificateTest.java
index e6e2a2b..3db7aca 100644
--- a/tests/tests/security/src/android/security/cts/CertificateTest.java
+++ b/tests/tests/security/src/android/security/cts/CertificateTest.java
@@ -16,9 +16,10 @@
package android.security.cts;
-import android.test.AndroidTestCase;
+import android.content.res.AssetManager;
+import android.test.InstrumentationTestCase;
-import java.io.FileInputStream;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
@@ -27,6 +28,7 @@
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Collections;
@@ -34,7 +36,7 @@
import java.util.List;
import java.util.Set;
-public class CertificateTest extends AndroidTestCase {
+public class CertificateTest extends InstrumentationTestCase {
public void testNoRemovedCertificates() throws Exception {
Set<String> expectedCertificates = new HashSet<String>(
@@ -45,16 +47,58 @@
}
/**
- * {@see OEMCertificateWhitelist#OEM_CERTIFICATE_WHITELIST} for more information on this test.
+ * If you fail CTS as a result of adding a root CA that is not part of the Android root CA
+ * store, please see the following.
+ *
+ * First, this test exists because adding untrustworthy root CAs to a device has a very
+ * significant security impact. In the worst case, adding a rogue CA can permanently compromise
+ * the confidentiality and integrity of your users' network traffic. Because of this risk,
+ * adding new certificates should be done sparingly and as a last resort -- never as a first
+ * response or short term fix. Before attempting to modify this test, please consider whether
+ * adding a new certificate authority is in your users' best interests.
+ *
+ * Second, because the addition of a new root CA by an OEM can have such dire consequences for
+ * so many people it is imperative that it be done transparently and in the open. Any request to
+ * modify the certificate list used by this test must have a corresponding change in AOSP
+ * (one certificate per change) authored by the OEM in question and including:
+ *
+ * - the certificate in question:
+ * - The certificate must be in a file under
+ * cts/tests/tests/security/assets/oem_cacerts, in PEM (Privacy-enhanced Electronic
+ * Mail) format, with the textual representation of the certificate following the PEM
+ * section.
+ * - The file name must be in the format of <hash>.<n> where "hash" is the subject hash
+ * produced by:
+ * openssl x509 -in cert_file -subject_hash -noout
+ * and the "n" is a unique integer identifier starting at 0 to deal with collisions.
+ * See OpenSSL's c_rehash manpage for details.
+ * - cts/tests/tests/security/tools/format_cert.sh helps meet the above requirements.
+ *
+ * - information about who created and maintains both the certificate and the corresponding
+ * keypair.
+ *
+ * - information about what the certificate is to be used for and why the certificate is
+ * appropriate for inclusion.
+ *
+ * - a statement from the OEM indicating that they have sufficient confidence in the
+ * security of the key, the security practices of the issuer, and the validity of the
+ * intended use that they believe adding the certificate is not detrimental to the
+ * security of the user.
+ *
+ * Finally, please note that this is not the usual process for adding root CAs to Android. If
+ * you have a certificate that you believe should be present on all Android devices, please file
+ * a public bug at https://code.google.com/p/android/issues/entry or http://b.android.com to
+ * seek resolution.
+ *
+ * For questions, comments, and code reviews please contact security@android.com.
*/
public void testNoAddedCertificates() throws Exception {
- Set<String> oemCertificateWhitelist = new HashSet<String>(
- Arrays.asList(OEMCertificateWhitelist.OEM_CERTIFICATE_WHITELIST));
+ Set<String> oemWhitelistedCertificates = getOemWhitelistedCertificates();
Set<String> expectedCertificates = new HashSet<String>(
Arrays.asList(CertificateData.CERTIFICATE_DATA));
Set<String> deviceCertificates = getDeviceCertificates();
deviceCertificates.removeAll(expectedCertificates);
- deviceCertificates.removeAll(oemCertificateWhitelist);
+ deviceCertificates.removeAll(oemWhitelistedCertificates);
assertEquals("Unknown CA certificates", Collections.EMPTY_SET, deviceCertificates);
}
@@ -88,6 +132,30 @@
return certificates;
}
+ private static final String ASSETS_DIR_OEM_CERTS = "oem_cacerts";
+
+ private Set<String> getOemWhitelistedCertificates() throws Exception {
+ Set<String> certificates = new HashSet<String>();
+ CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+ AssetManager assetManager = getInstrumentation().getContext().getAssets();
+ for (String path : assetManager.list(ASSETS_DIR_OEM_CERTS)) {
+ File certAssetFile = new File(ASSETS_DIR_OEM_CERTS, path);
+ InputStream in = null;
+ try {
+ in = assetManager.open(certAssetFile.toString());
+ X509Certificate certificate = (X509Certificate) certFactory.generateCertificate(in);
+ certificates.add(getFingerprint(certificate));
+ } catch (Exception e) {
+ throw new Exception("Failed to load certificate from asset: " + certAssetFile, e);
+ } finally {
+ if (in != null) {
+ in.close();
+ }
+ }
+ }
+ return certificates;
+ }
+
private String getFingerprint(X509Certificate certificate) throws CertificateEncodingException,
NoSuchAlgorithmException {
MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
diff --git a/tests/tests/security/src/android/security/cts/OEMCertificateWhitelist.java b/tests/tests/security/src/android/security/cts/OEMCertificateWhitelist.java
deleted file mode 100644
index 024c15f..0000000
--- a/tests/tests/security/src/android/security/cts/OEMCertificateWhitelist.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2013 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 android.security.cts;
-
-class OEMCertificateWhitelist {
-
- /**
- * If you fail CTS as a result of adding a root CA that is not part
- * of the Android root CA store, please see the following.
- *
- * First, this test exists because adding untrustworthy root CAs
- * to a device has a very significant security impact. In the worst
- * case, adding a rogue CA to this list can permanently compromise
- * the confidentiality and integrity of your users' network traffic.
- * Because of this risk, adding new certificates should be done
- * sparingly and as a last resort- never as a first response or
- * short term fix. Before attempting to modify this test, please
- * consider whether adding a new certificate authority is in your
- * users' best interests.
- *
- * Second, because the addition of a new root CA by an OEM can have
- * such dire consequences for so many people it is imperative that
- * it be done transparently and in the open. Any request to modify
- * this list must have a corresponding change in AOSP authored by
- * the OEM in question and including:
- *
- * - the certificate in question.
- *
- * - information about who created and maintains
- * both the certificate and the corresponding keypair.
- *
- * - information about what the certificate is to be used
- * for and why the certificate is appropriate for inclusion.
- *
- * - a statement from the OEM indicating that they have
- * sufficient confidence in the security of the key, the
- * security practices of the issuer, and the validity
- * of the intended use that they believe adding the
- * certificate is not detrimental to the security of the
- * user.
- *
- * Finally, please note that this is not the usual process for
- * adding root CAs to Android. If you have a certificate that you
- * believe should be present on all Android devices, please file a
- * public bug at https://code.google.com/p/android/issues/entry or
- * http://b.android.com to seek resolution.
- *
- * For questions, comments, and code reviews please contact
- * security@android.com.
- */
- static final String[] OEM_CERTIFICATE_WHITELIST = {};
-
-}
diff --git a/tests/tests/security/tools/format_cert.sh b/tests/tests/security/tools/format_cert.sh
new file mode 100755
index 0000000..94407a0
--- /dev/null
+++ b/tests/tests/security/tools/format_cert.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+# Outputs the provided certificate (PEM or DER) in a format used by CTS tests.
+# The format is PEM block, followed by the textual representation of the
+# certificate, followed by the SHA-1 fingerprint.
+
+# OpenSSL binary built from this Android source
+OPENSSL="$ANDROID_HOST_OUT/bin/openssl"
+if [ "$ANDROID_HOST_OUT" == "" ]; then
+ echo "Android build environment not set up"
+ echo
+ echo "Run the following from the root of the Android source tree:"
+ echo " . build/envsetup.sh && lunch"
+ exit 1
+fi
+if [ ! -f "$OPENSSL" ]; then
+ echo "openssl binary not found"
+ echo
+ echo "Run 'mmm external/openssl' or 'make openssl' from the root of the" \
+ "Android source tree to build it."
+ exit 1
+fi
+
+# Input file containing the certificate in PEM or DER format
+in_file="$1"
+
+# Output file. If not specified, the file will be named <hash>.0 where "hash"
+# is the certificate's subject hash produced by:
+# openssl x509 -in cert_file -subject_hash -noout
+out_file="$2"
+
+# Detect whether the input file is PEM or DER.
+in_form="pem"
+subject_hash=$("$OPENSSL" x509 -in "$in_file" -inform $in_form -subject_hash \
+ -noout 2>/dev/null)
+if [ "$?" != "0" ]; then
+ in_form="der"
+ subject_hash=$("$OPENSSL" x509 -in "$in_file" -inform $in_form -subject_hash \
+ -noout)
+ if [ "$?" != "0" ]; then
+ echo "Certificate file format is neither PEM nor DER"
+ exit 1
+ fi
+fi
+
+# Name the output file <hash>.0 if the name is not specified explicitly.
+if [ "$out_file" == "" ]; then
+ out_file="$subject_hash.0"
+ echo "Auto-generated output file name: $out_file"
+fi
+
+# Output the certificate in the target format
+"$OPENSSL" x509 -in "$in_file" -inform $in_form -outform pem > "$out_file" && \
+"$OPENSSL" x509 -in "$in_file" -inform $in_form -noout -text -fingerprint \
+ >> "$out_file"