diff options
Diffstat (limited to 'tests/src/com/android/settings/vpn2/CertInstallerHelper.java')
-rw-r--r-- | tests/src/com/android/settings/vpn2/CertInstallerHelper.java | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/tests/src/com/android/settings/vpn2/CertInstallerHelper.java b/tests/src/com/android/settings/vpn2/CertInstallerHelper.java new file mode 100644 index 0000000..f95893f --- /dev/null +++ b/tests/src/com/android/settings/vpn2/CertInstallerHelper.java @@ -0,0 +1,223 @@ +/* + * 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 com.android.settings.vpn2; + +import android.os.Environment; +import android.security.Credentials; +import android.security.KeyStore; +import android.util.Log; + +import com.android.internal.net.VpnProfile; +import com.android.org.bouncycastle.asn1.ASN1InputStream; +import com.android.org.bouncycastle.asn1.ASN1Sequence; +import com.android.org.bouncycastle.asn1.DEROctetString; +import com.android.org.bouncycastle.asn1.x509.BasicConstraints; + +import junit.framework.Assert; + +import libcore.io.Streams; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.KeyStore.PasswordProtection; +import java.security.KeyStore.PrivateKeyEntry; +import java.security.PrivateKey; +import java.security.UnrecoverableEntryException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; + +/** + * Certificate installer helper to extract information from a provided file + * and install certificates to keystore. + */ +public class CertInstallerHelper { + private static final String TAG = "CertInstallerHelper"; + /* Define a password to unlock keystore after it is reset */ + private static final String CERT_STORE_PASSWORD = "password"; + private final int mUid = KeyStore.UID_SELF; + private PrivateKey mUserKey; // private key + private X509Certificate mUserCert; // user certificate + private List<X509Certificate> mCaCerts = new ArrayList<X509Certificate>(); + private KeyStore mKeyStore = KeyStore.getInstance(); + + /** + * Unlock keystore and set password + */ + public CertInstallerHelper() { + mKeyStore.reset(); + mKeyStore.password(CERT_STORE_PASSWORD); + } + + private void extractCertificate(String certFile, String password) { + InputStream in = null; + final byte[] raw; + java.security.KeyStore keystore = null; + try { + // Read .p12 file from SDCARD and extract with password + in = new FileInputStream(new File( + Environment.getExternalStorageDirectory(), certFile)); + raw = Streams.readFully(in); + + keystore = java.security.KeyStore.getInstance("PKCS12"); + PasswordProtection passwordProtection = new PasswordProtection(password.toCharArray()); + keystore.load(new ByteArrayInputStream(raw), passwordProtection.getPassword()); + + // Install certificates and private keys + Enumeration<String> aliases = keystore.aliases(); + if (!aliases.hasMoreElements()) { + Assert.fail("key store failed to put in keychain"); + } + ArrayList<String> aliasesList = Collections.list(aliases); + // The keystore is initialized for each test case, there will + // be only one alias in the keystore + Assert.assertEquals(1, aliasesList.size()); + String alias = aliasesList.get(0); + java.security.KeyStore.Entry entry = keystore.getEntry(alias, passwordProtection); + Log.d(TAG, "extracted alias = " + alias + ", entry=" + entry.getClass()); + + if (entry instanceof PrivateKeyEntry) { + Assert.assertTrue(installFrom((PrivateKeyEntry) entry)); + } + } catch (IOException e) { + Assert.fail("Failed to read certficate: " + e); + } catch (KeyStoreException e) { + Log.e(TAG, "failed to extract certificate" + e); + } catch (NoSuchAlgorithmException e) { + Log.e(TAG, "failed to extract certificate" + e); + } catch (CertificateException e) { + Log.e(TAG, "failed to extract certificate" + e); + } catch (UnrecoverableEntryException e) { + Log.e(TAG, "failed to extract certificate" + e); + } + finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + Log.e(TAG, "close FileInputStream error: " + e); + } + } + } + } + + /** + * Extract private keys, user certificates and ca certificates + */ + private synchronized boolean installFrom(PrivateKeyEntry entry) { + mUserKey = entry.getPrivateKey(); + mUserCert = (X509Certificate) entry.getCertificate(); + + Certificate[] certs = entry.getCertificateChain(); + Log.d(TAG, "# certs extracted = " + certs.length); + mCaCerts = new ArrayList<X509Certificate>(certs.length); + for (Certificate c : certs) { + X509Certificate cert = (X509Certificate) c; + if (isCa(cert)) { + mCaCerts.add(cert); + } + } + Log.d(TAG, "# ca certs extracted = " + mCaCerts.size()); + return true; + } + + private boolean isCa(X509Certificate cert) { + try { + byte[] asn1EncodedBytes = cert.getExtensionValue("2.5.29.19"); + if (asn1EncodedBytes == null) { + return false; + } + DEROctetString derOctetString = (DEROctetString) + new ASN1InputStream(asn1EncodedBytes).readObject(); + byte[] octets = derOctetString.getOctets(); + ASN1Sequence sequence = (ASN1Sequence) + new ASN1InputStream(octets).readObject(); + return BasicConstraints.getInstance(sequence).isCA(); + } catch (IOException e) { + return false; + } + } + + /** + * Extract certificate from the given file, and install it to keystore + * @param name certificate name + * @param certFile .p12 file which includes certificates + * @param password password to extract the .p12 file + */ + public void installCertificate(VpnProfile profile, String certFile, String password) { + // extract private keys, certificates from the provided file + extractCertificate(certFile, password); + // install certificate to the keystore + int flags = KeyStore.FLAG_ENCRYPTED; + try { + if (mUserKey != null) { + Log.v(TAG, "has private key"); + String key = Credentials.USER_PRIVATE_KEY + profile.ipsecUserCert; + byte[] value = mUserKey.getEncoded(); + + if (!mKeyStore.importKey(key, value, mUid, flags)) { + Log.e(TAG, "Failed to install " + key + " as user " + mUid); + return; + } + Log.v(TAG, "install " + key + " as user " + mUid + " is successful"); + } + + if (mUserCert != null) { + String certName = Credentials.USER_CERTIFICATE + profile.ipsecUserCert; + byte[] certData = Credentials.convertToPem(mUserCert); + + if (!mKeyStore.put(certName, certData, mUid, flags)) { + Log.e(TAG, "Failed to install " + certName + " as user " + mUid); + return; + } + Log.v(TAG, "install " + certName + " as user" + mUid + " is successful."); + } + + if (!mCaCerts.isEmpty()) { + String caListName = Credentials.CA_CERTIFICATE + profile.ipsecCaCert; + X509Certificate[] caCerts = mCaCerts.toArray(new X509Certificate[mCaCerts.size()]); + byte[] caListData = Credentials.convertToPem(caCerts); + + if (!mKeyStore.put(caListName, caListData, mUid, flags)) { + Log.e(TAG, "Failed to install " + caListName + " as user " + mUid); + return; + } + Log.v(TAG, " install " + caListName + " as user " + mUid + " is successful"); + } + } catch (CertificateEncodingException e) { + Log.e(TAG, "Exception while convert certificates to pem " + e); + throw new AssertionError(e); + } catch (IOException e) { + Log.e(TAG, "IOException while convert to pem: " + e); + } + } + + public int getUid() { + return mUid; + } +} |