Add legacy VPN test framework and test cases
- VpnProfileParser can parse VPN profiles from an xml file - CertInstallerHelper installs keys and certificates to keystore - VpnTests includes all test cases Change-Id: Ib5ce33e770ee4f82bea153f9b5c5cf3802f95b0c
This commit is contained in:
223
tests/src/com/android/settings/vpn2/CertInstallerHelper.java
Normal file
223
tests/src/com/android/settings/vpn2/CertInstallerHelper.java
Normal file
@@ -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;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user