Loading keystore/java/android/security/CertTool.java 0 → 100644 +143 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2009 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; import android.content.Context; import android.content.Intent; import android.security.Keystore; import android.text.TextUtils; /** * The CertTool class provides the functions to list the certs/keys, * generate the certificate request(csr) and store the certificate into * keystore. * * {@hide} */ public class CertTool { public static final String ACTION_ADD_CREDENTIAL = "android.security.ADD_CREDENTIAL"; public static final String KEY_TYPE_NAME = "typeName"; public static final String KEY_ITEM = "item"; public static final String KEY_NAMESPACE = "namespace"; public static final String KEY_DESCRIPTION = "description"; private static final String TAG = "CertTool"; private static final String TITLE_CA_CERT = "CA Certificate"; private static final String TITLE_USER_CERT = "User Certificate"; private static final String TITLE_PKCS12_KEYSTORE = "PKCS12 Keystore"; private static final String TITLE_PRIVATE_KEY = "Private Key"; private static final String UNKNOWN = "Unknown"; private static final String ISSUER_NAME = "Issuer Name:"; private static final String DISTINCT_NAME = "Distinct Name:"; private static final String CA_CERTIFICATE = "CACERT"; private static final String USER_CERTIFICATE = "USRCERT"; private static final String USER_KEY = "USRKEY"; private static final String KEYNAME_DELIMITER = " "; private static final Keystore keystore = Keystore.getInstance(); private native String generateCertificateRequest(int bits, String subject); private native boolean isPkcs12Keystore(byte[] data); private native int generateX509Certificate(byte[] data); private native boolean isCaCertificate(int handle); private native String getIssuerDN(int handle); private native String getCertificateDN(int handle); private native String getPrivateKeyPEM(int handle); private native void freeX509Certificate(int handle); public String getUserPrivateKey(String key) { return USER_KEY + KEYNAME_DELIMITER + key; } public String getUserCertificate(String key) { return USER_CERTIFICATE + KEYNAME_DELIMITER + key; } public String getCaCertificate(String key) { return CA_CERTIFICATE + KEYNAME_DELIMITER + key; } public String[] getAllUserCertificateKeys() { return keystore.listKeys(USER_KEY); } public String[] getAllCaCertificateKeys() { return keystore.listKeys(CA_CERTIFICATE); } public String[] getSupportedKeyStrenghs() { return new String[] {"High Grade", "Medium Grade"}; } private int getKeyLength(int index) { if (index == 0) return 2048; return 1024; } public String generateKeyPair(int keyStrengthIndex, String challenge, String dirName) { return generateCertificateRequest(getKeyLength(keyStrengthIndex), dirName); } private Intent prepareIntent(String title, byte[] data, String namespace, String issuer, String distinctName) { Intent intent = new Intent(ACTION_ADD_CREDENTIAL); intent.putExtra(KEY_TYPE_NAME, title); intent.putExtra(KEY_ITEM + "0", data); intent.putExtra(KEY_NAMESPACE + "0", namespace); intent.putExtra(KEY_DESCRIPTION + "0", ISSUER_NAME + issuer); intent.putExtra(KEY_DESCRIPTION + "1", DISTINCT_NAME + distinctName); return intent; } private void addExtraIntentInfo(Intent intent, String namespace, String data) { intent.putExtra(KEY_ITEM + "1", data); intent.putExtra(KEY_NAMESPACE + "1", namespace); } public synchronized void addCertificate(byte[] data, Context context) { int handle; Intent intent = null; if (isPkcs12Keystore(data)) { intent = prepareIntent(TITLE_PKCS12_KEYSTORE, data, USER_KEY, UNKNOWN, UNKNOWN); } else if ((handle = generateX509Certificate(data)) != 0) { String issuer = getIssuerDN(handle); String distinctName = getCertificateDN(handle); String privateKeyPEM = getPrivateKeyPEM(handle); if (isCaCertificate(handle)) { intent = prepareIntent(TITLE_CA_CERT, data, CA_CERTIFICATE, issuer, distinctName); } else { intent = prepareIntent(TITLE_USER_CERT, data, USER_CERTIFICATE, issuer, distinctName); if (!TextUtils.isEmpty(privateKeyPEM)) { addExtraIntentInfo(intent, USER_KEY, privateKeyPEM); } } freeX509Certificate(handle); } if (intent != null) context.startActivity(intent); } } keystore/java/android/security/Keystore.java +92 −106 Original line number Original line Diff line number Diff line Loading @@ -20,6 +20,7 @@ package android.security; * The Keystore class provides the functions to list the certs/keys in keystore. * The Keystore class provides the functions to list the certs/keys in keystore. * {@hide} * {@hide} */ */ public abstract class Keystore { public abstract class Keystore { private static final String TAG = "Keystore"; private static final String TAG = "Keystore"; private static final String[] NOTFOUND = new String[0]; private static final String[] NOTFOUND = new String[0]; Loading @@ -30,25 +31,18 @@ public abstract class Keystore { return new FileKeystore(); return new FileKeystore(); } } // for compatiblity, start from here public abstract int lock(); /** public abstract int unlock(String password); */ public abstract int getState(); public abstract String getUserkey(String key); public abstract int changePassword(String oldPassword, String newPassword); public abstract int setPassword(String firstPassword); /** public abstract String[] listKeys(String namespace); */ public abstract int put(String namespace, String keyname, String value); public abstract String getCertificate(String key); public abstract String get(String namespace, String keyname); public abstract int remove(String namespace, String keyname); /** public abstract int reset(); */ public abstract String[] getAllCertificateKeys(); /** */ public abstract String[] getAllUserkeyKeys(); // to here // TODO: for migrating to the mini-keystore, clean up from here /** /** */ */ public abstract String getCaCertificate(String key); public abstract String getCaCertificate(String key); Loading Loading @@ -89,101 +83,41 @@ public abstract class Keystore { int keyStrengthIndex, String challenge, String organizations); int keyStrengthIndex, String challenge, String organizations); public abstract void addCertificate(byte[] cert); public abstract void addCertificate(byte[] cert); // to here private static class FileKeystore extends Keystore { private static class FileKeystore extends Keystore { private static final String SERVICE_NAME = "keystore"; private static final String SERVICE_NAME = "keystore"; private static final String LIST_CA_CERTIFICATES = "listcacerts"; private static final String CA_CERTIFICATE = "CaCertificate"; private static final String LIST_USER_CERTIFICATES = "listusercerts"; private static final String USER_CERTIFICATE = "UserCertificate"; private static final String GET_CA_CERTIFICATE = "getcacert"; private static final String USER_KEY = "UserPrivateKey"; private static final String GET_USER_CERTIFICATE = "getusercert"; private static final String COMMAND_DELIMITER = " "; private static final String GET_USER_KEY = "getuserkey"; private static final String ADD_CA_CERTIFICATE = "addcacert"; private static final String ADD_USER_CERTIFICATE = "addusercert"; private static final String ADD_USER_KEY = "adduserkey"; private static final String COMMAND_DELIMITER = "\t"; private static final ServiceCommand mServiceCommand = private static final ServiceCommand mServiceCommand = new ServiceCommand(SERVICE_NAME); new ServiceCommand(SERVICE_NAME); // for compatiblity, start from here // TODO: for migrating to the mini-keystore, start from here private static final String LIST_CERTIFICATES = "listcerts"; private static final String LIST_USERKEYS = "listuserkeys"; private static final String PATH = "/data/misc/keystore/"; private static final String USERKEY_PATH = PATH + "userkeys/"; private static final String CERT_PATH = PATH + "certs/"; @Override public String getUserkey(String key) { return USERKEY_PATH + key; } @Override public String getCertificate(String key) { return CERT_PATH + key; } @Override public String[] getAllCertificateKeys() { try { String result = mServiceCommand.execute(LIST_CERTIFICATES); if (result != null) return result.split("\\s+"); return NOTFOUND; } catch (NumberFormatException ex) { return NOTFOUND; } } @Override public String[] getAllUserkeyKeys() { try { String result = mServiceCommand.execute(LIST_USERKEYS); if (result != null) return result.split("\\s+"); return NOTFOUND; } catch (NumberFormatException ex) { return NOTFOUND; } } // to here @Override @Override public String getUserPrivateKey(String key) { public String getUserPrivateKey(String key) { return mServiceCommand.execute( return ""; GET_USER_KEY + COMMAND_DELIMITER + key); } } @Override @Override public String getUserCertificate(String key) { public String getUserCertificate(String key) { return mServiceCommand.execute( return ""; GET_USER_CERTIFICATE + COMMAND_DELIMITER + key); } } @Override @Override public String getCaCertificate(String key) { public String getCaCertificate(String key) { return mServiceCommand.execute( return ""; GET_CA_CERTIFICATE + COMMAND_DELIMITER + key); } } @Override @Override public String[] getAllUserCertificateKeys() { public String[] getAllUserCertificateKeys() { try { return new String[0]; String result = mServiceCommand.execute(LIST_USER_CERTIFICATES); if (result != null) return result.split("\\s+"); return NOTFOUND; } catch (NumberFormatException ex) { return NOTFOUND; } } } @Override @Override public String[] getAllCaCertificateKeys() { public String[] getAllCaCertificateKeys() { try { return new String[0]; String result = mServiceCommand.execute(LIST_CA_CERTIFICATES); if (result != null) return result.split("\\s+"); return NOTFOUND; } catch (NumberFormatException ex) { return NOTFOUND; } } } @Override @Override Loading Loading @@ -221,25 +155,77 @@ public abstract class Keystore { // TODO: real implementation // TODO: real implementation } } private boolean addUserCertificate(String key, String certificate, // to here String privateKey) { if(mServiceCommand.execute(ADD_USER_CERTIFICATE + COMMAND_DELIMITER @Override + key + COMMAND_DELIMITER + certificate) != null) { public int lock() { if (mServiceCommand.execute(ADD_USER_KEY + COMMAND_DELIMITER Reply result = mServiceCommand.execute(ServiceCommand.LOCK, null); + key + COMMAND_DELIMITER + privateKey) != null) { return (result != null) ? result.returnCode : -1; return true; } } @Override public int unlock(String password) { Reply result = mServiceCommand.execute(ServiceCommand.UNLOCK, password); return (result != null) ? result.returnCode : -1; } } return false; @Override public int getState() { Reply result = mServiceCommand.execute(ServiceCommand.GET_STATE, null); return (result != null) ? result.returnCode : -1; } } private boolean addCaCertificate(String key, String content) { @Override if (mServiceCommand.execute(ADD_CA_CERTIFICATE + COMMAND_DELIMITER public int changePassword(String oldPassword, String newPassword) { + key + COMMAND_DELIMITER + content) != null) { Reply result = mServiceCommand.execute(ServiceCommand.PASSWD, return true; oldPassword + " " + newPassword); return (result != null) ? result.returnCode : -1; } } return false; @Override public int setPassword(String firstPassword) { Reply result = mServiceCommand.execute(ServiceCommand.PASSWD, firstPassword); return (result != null) ? result.returnCode : -1; } } @Override public String[] listKeys(String namespace) { Reply result = mServiceCommand.execute(ServiceCommand.LIST_KEYS, namespace); return (result != null) ? ((result.returnCode != 0) ? NOTFOUND : new String(result.data, 0, result.len).split("\\s+")) : NOTFOUND; } @Override public int put(String namespace, String keyname, String value) { Reply result = mServiceCommand.execute(ServiceCommand.PUT_KEY, namespace + " " + keyname + " " + value); return (result != null) ? result.returnCode : -1; } @Override public String get(String namespace, String keyname) { Reply result = mServiceCommand.execute(ServiceCommand.GET_KEY, namespace + " " + keyname); return (result != null) ? ((result.returnCode != 0) ? null : new String(result.data, 0, result.len)) : null; } @Override public int remove(String namespace, String keyname) { Reply result = mServiceCommand.execute(ServiceCommand.REMOVE_KEY, namespace + " " + keyname); return (result != null) ? result.returnCode : -1; } @Override public int reset() { Reply result = mServiceCommand.execute(ServiceCommand.RESET, null); return (result != null) ? result.returnCode : -1; } } } } } keystore/java/android/security/Reply.java 0 → 100644 +26 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2009 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; /* * {@hide} */ public class Reply { public int len; public int returnCode; public byte[] data = new byte[ServiceCommand.BUFFER_LENGTH]; } keystore/java/android/security/ServiceCommand.java +53 −35 Original line number Original line Diff line number Diff line Loading @@ -35,15 +35,25 @@ public class ServiceCommand { public static final String SUCCESS = "0"; public static final String SUCCESS = "0"; public static final String FAILED = "-1"; public static final String FAILED = "-1"; // Opcodes for keystore commands. public static final int LOCK = 0; public static final int UNLOCK = 1; public static final int PASSWD = 2; public static final int GET_STATE = 3; public static final int LIST_KEYS = 4; public static final int GET_KEY = 5; public static final int PUT_KEY = 6; public static final int REMOVE_KEY = 7; public static final int RESET = 8; public static final int MAX_CMD_INDEX = 9; public static final int BUFFER_LENGTH = 4096; private String mServiceName; private String mServiceName; private String mTag; private String mTag; private InputStream mIn; private InputStream mIn; private OutputStream mOut; private OutputStream mOut; private LocalSocket mSocket; private LocalSocket mSocket; private static final int BUFFER_LENGTH = 1024; private byte buf[] = new byte[BUFFER_LENGTH]; private int buflen = 0; private boolean connect() { private boolean connect() { if (mSocket != null) { if (mSocket != null) { Loading Loading @@ -104,35 +114,47 @@ public class ServiceCommand { return false; return false; } } private boolean readReply() { private Reply readReply() { int len, ret; byte buf[] = new byte[4]; buflen = 0; Reply reply = new Reply(); if (!readBytes(buf, 2)) return false; if (!readBytes(buf, 4)) return null; ret = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8); reply.len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8) | if (ret != 0) return false; ((((int) buf[2]) & 0xff) << 16) | ((((int) buf[3]) & 0xff) << 24); if (!readBytes(buf, 2)) return false; if (!readBytes(buf, 4)) return null; len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8); reply.returnCode = (((int) buf[0]) & 0xff) | if (len > BUFFER_LENGTH) { ((((int) buf[1]) & 0xff) << 8) | Log.e(mTag,"invalid reply length (" + len + ")"); ((((int) buf[2]) & 0xff) << 16) | ((((int) buf[3]) & 0xff) << 24); if (reply.len > BUFFER_LENGTH) { Log.e(mTag,"invalid reply length (" + reply.len + ")"); disconnect(); disconnect(); return false; return null; } } if (!readBytes(buf, len)) return false; if (!readBytes(reply.data, reply.len)) return null; buflen = len; return reply; return true; } } private boolean writeCommand(String _cmd) { private boolean writeCommand(int cmd, String _data) { byte[] cmd = _cmd.getBytes(); byte buf[] = new byte[8]; int len = cmd.length; byte[] data = _data.getBytes(); if ((len < 1) || (len > BUFFER_LENGTH)) return false; int len = data.length; // the length of data buf[0] = (byte) (len & 0xff); buf[0] = (byte) (len & 0xff); buf[1] = (byte) ((len >> 8) & 0xff); buf[1] = (byte) ((len >> 8) & 0xff); buf[2] = (byte) ((len >> 16) & 0xff); buf[3] = (byte) ((len >> 24) & 0xff); // the opcode of the command buf[4] = (byte) (cmd & 0xff); buf[5] = (byte) ((cmd >> 8) & 0xff); buf[6] = (byte) ((cmd >> 16) & 0xff); buf[7] = (byte) ((cmd >> 24) & 0xff); try { try { mOut.write(buf, 0, 2); mOut.write(buf, 0, 8); mOut.write(cmd, 0, len); mOut.write(data, 0, len); } catch (IOException ex) { } catch (IOException ex) { Log.e(mTag,"write error"); Log.e(mTag,"write error"); disconnect(); disconnect(); Loading @@ -141,32 +163,28 @@ public class ServiceCommand { return true; return true; } } private String executeCommand(String cmd) { private Reply executeCommand(int cmd, String data) { if (!writeCommand(cmd)) { if (!writeCommand(cmd, data)) { /* If service died and restarted in the background /* If service died and restarted in the background * (unlikely but possible) we'll fail on the next * (unlikely but possible) we'll fail on the next * write (this one). Try to reconnect and write * write (this one). Try to reconnect and write * the command one more time before giving up. * the command one more time before giving up. */ */ Log.e(mTag, "write command failed? reconnect!"); Log.e(mTag, "write command failed? reconnect!"); if (!connect() || !writeCommand(cmd)) { if (!connect() || !writeCommand(cmd, data)) { return null; return null; } } } } if (readReply()) { return readReply(); return new String(buf, 0, buflen); } else { return null; } } } public synchronized String execute(String cmd) { public synchronized Reply execute(int cmd, String data) { String result; Reply result; if (!connect()) { if (!connect()) { Log.e(mTag, "connection failed"); Log.e(mTag, "connection failed"); return null; return null; } } result = executeCommand(cmd); result = executeCommand(cmd, data); disconnect(); disconnect(); return result; return result; } } Loading keystore/jni/Android.mk 0 → 100644 +31 −0 Original line number Original line Diff line number Diff line LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ cert.c certtool.c LOCAL_C_INCLUDES += \ $(JNI_H_INCLUDE) \ external/openssl/include LOCAL_SHARED_LIBRARIES := \ libcutils \ libnativehelper \ libutils \ libcrypto ifeq ($(TARGET_SIMULATOR),true) ifeq ($(TARGET_OS),linux) ifeq ($(TARGET_ARCH),x86) LOCAL_LDLIBS += -lpthread -ldl -lrt -lssl endif endif endif ifeq ($(WITH_MALLOC_LEAK_CHECK),true) LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK endif LOCAL_MODULE:= libcerttool_jni include $(BUILD_SHARED_LIBRARY) Loading
keystore/java/android/security/CertTool.java 0 → 100644 +143 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2009 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; import android.content.Context; import android.content.Intent; import android.security.Keystore; import android.text.TextUtils; /** * The CertTool class provides the functions to list the certs/keys, * generate the certificate request(csr) and store the certificate into * keystore. * * {@hide} */ public class CertTool { public static final String ACTION_ADD_CREDENTIAL = "android.security.ADD_CREDENTIAL"; public static final String KEY_TYPE_NAME = "typeName"; public static final String KEY_ITEM = "item"; public static final String KEY_NAMESPACE = "namespace"; public static final String KEY_DESCRIPTION = "description"; private static final String TAG = "CertTool"; private static final String TITLE_CA_CERT = "CA Certificate"; private static final String TITLE_USER_CERT = "User Certificate"; private static final String TITLE_PKCS12_KEYSTORE = "PKCS12 Keystore"; private static final String TITLE_PRIVATE_KEY = "Private Key"; private static final String UNKNOWN = "Unknown"; private static final String ISSUER_NAME = "Issuer Name:"; private static final String DISTINCT_NAME = "Distinct Name:"; private static final String CA_CERTIFICATE = "CACERT"; private static final String USER_CERTIFICATE = "USRCERT"; private static final String USER_KEY = "USRKEY"; private static final String KEYNAME_DELIMITER = " "; private static final Keystore keystore = Keystore.getInstance(); private native String generateCertificateRequest(int bits, String subject); private native boolean isPkcs12Keystore(byte[] data); private native int generateX509Certificate(byte[] data); private native boolean isCaCertificate(int handle); private native String getIssuerDN(int handle); private native String getCertificateDN(int handle); private native String getPrivateKeyPEM(int handle); private native void freeX509Certificate(int handle); public String getUserPrivateKey(String key) { return USER_KEY + KEYNAME_DELIMITER + key; } public String getUserCertificate(String key) { return USER_CERTIFICATE + KEYNAME_DELIMITER + key; } public String getCaCertificate(String key) { return CA_CERTIFICATE + KEYNAME_DELIMITER + key; } public String[] getAllUserCertificateKeys() { return keystore.listKeys(USER_KEY); } public String[] getAllCaCertificateKeys() { return keystore.listKeys(CA_CERTIFICATE); } public String[] getSupportedKeyStrenghs() { return new String[] {"High Grade", "Medium Grade"}; } private int getKeyLength(int index) { if (index == 0) return 2048; return 1024; } public String generateKeyPair(int keyStrengthIndex, String challenge, String dirName) { return generateCertificateRequest(getKeyLength(keyStrengthIndex), dirName); } private Intent prepareIntent(String title, byte[] data, String namespace, String issuer, String distinctName) { Intent intent = new Intent(ACTION_ADD_CREDENTIAL); intent.putExtra(KEY_TYPE_NAME, title); intent.putExtra(KEY_ITEM + "0", data); intent.putExtra(KEY_NAMESPACE + "0", namespace); intent.putExtra(KEY_DESCRIPTION + "0", ISSUER_NAME + issuer); intent.putExtra(KEY_DESCRIPTION + "1", DISTINCT_NAME + distinctName); return intent; } private void addExtraIntentInfo(Intent intent, String namespace, String data) { intent.putExtra(KEY_ITEM + "1", data); intent.putExtra(KEY_NAMESPACE + "1", namespace); } public synchronized void addCertificate(byte[] data, Context context) { int handle; Intent intent = null; if (isPkcs12Keystore(data)) { intent = prepareIntent(TITLE_PKCS12_KEYSTORE, data, USER_KEY, UNKNOWN, UNKNOWN); } else if ((handle = generateX509Certificate(data)) != 0) { String issuer = getIssuerDN(handle); String distinctName = getCertificateDN(handle); String privateKeyPEM = getPrivateKeyPEM(handle); if (isCaCertificate(handle)) { intent = prepareIntent(TITLE_CA_CERT, data, CA_CERTIFICATE, issuer, distinctName); } else { intent = prepareIntent(TITLE_USER_CERT, data, USER_CERTIFICATE, issuer, distinctName); if (!TextUtils.isEmpty(privateKeyPEM)) { addExtraIntentInfo(intent, USER_KEY, privateKeyPEM); } } freeX509Certificate(handle); } if (intent != null) context.startActivity(intent); } }
keystore/java/android/security/Keystore.java +92 −106 Original line number Original line Diff line number Diff line Loading @@ -20,6 +20,7 @@ package android.security; * The Keystore class provides the functions to list the certs/keys in keystore. * The Keystore class provides the functions to list the certs/keys in keystore. * {@hide} * {@hide} */ */ public abstract class Keystore { public abstract class Keystore { private static final String TAG = "Keystore"; private static final String TAG = "Keystore"; private static final String[] NOTFOUND = new String[0]; private static final String[] NOTFOUND = new String[0]; Loading @@ -30,25 +31,18 @@ public abstract class Keystore { return new FileKeystore(); return new FileKeystore(); } } // for compatiblity, start from here public abstract int lock(); /** public abstract int unlock(String password); */ public abstract int getState(); public abstract String getUserkey(String key); public abstract int changePassword(String oldPassword, String newPassword); public abstract int setPassword(String firstPassword); /** public abstract String[] listKeys(String namespace); */ public abstract int put(String namespace, String keyname, String value); public abstract String getCertificate(String key); public abstract String get(String namespace, String keyname); public abstract int remove(String namespace, String keyname); /** public abstract int reset(); */ public abstract String[] getAllCertificateKeys(); /** */ public abstract String[] getAllUserkeyKeys(); // to here // TODO: for migrating to the mini-keystore, clean up from here /** /** */ */ public abstract String getCaCertificate(String key); public abstract String getCaCertificate(String key); Loading Loading @@ -89,101 +83,41 @@ public abstract class Keystore { int keyStrengthIndex, String challenge, String organizations); int keyStrengthIndex, String challenge, String organizations); public abstract void addCertificate(byte[] cert); public abstract void addCertificate(byte[] cert); // to here private static class FileKeystore extends Keystore { private static class FileKeystore extends Keystore { private static final String SERVICE_NAME = "keystore"; private static final String SERVICE_NAME = "keystore"; private static final String LIST_CA_CERTIFICATES = "listcacerts"; private static final String CA_CERTIFICATE = "CaCertificate"; private static final String LIST_USER_CERTIFICATES = "listusercerts"; private static final String USER_CERTIFICATE = "UserCertificate"; private static final String GET_CA_CERTIFICATE = "getcacert"; private static final String USER_KEY = "UserPrivateKey"; private static final String GET_USER_CERTIFICATE = "getusercert"; private static final String COMMAND_DELIMITER = " "; private static final String GET_USER_KEY = "getuserkey"; private static final String ADD_CA_CERTIFICATE = "addcacert"; private static final String ADD_USER_CERTIFICATE = "addusercert"; private static final String ADD_USER_KEY = "adduserkey"; private static final String COMMAND_DELIMITER = "\t"; private static final ServiceCommand mServiceCommand = private static final ServiceCommand mServiceCommand = new ServiceCommand(SERVICE_NAME); new ServiceCommand(SERVICE_NAME); // for compatiblity, start from here // TODO: for migrating to the mini-keystore, start from here private static final String LIST_CERTIFICATES = "listcerts"; private static final String LIST_USERKEYS = "listuserkeys"; private static final String PATH = "/data/misc/keystore/"; private static final String USERKEY_PATH = PATH + "userkeys/"; private static final String CERT_PATH = PATH + "certs/"; @Override public String getUserkey(String key) { return USERKEY_PATH + key; } @Override public String getCertificate(String key) { return CERT_PATH + key; } @Override public String[] getAllCertificateKeys() { try { String result = mServiceCommand.execute(LIST_CERTIFICATES); if (result != null) return result.split("\\s+"); return NOTFOUND; } catch (NumberFormatException ex) { return NOTFOUND; } } @Override public String[] getAllUserkeyKeys() { try { String result = mServiceCommand.execute(LIST_USERKEYS); if (result != null) return result.split("\\s+"); return NOTFOUND; } catch (NumberFormatException ex) { return NOTFOUND; } } // to here @Override @Override public String getUserPrivateKey(String key) { public String getUserPrivateKey(String key) { return mServiceCommand.execute( return ""; GET_USER_KEY + COMMAND_DELIMITER + key); } } @Override @Override public String getUserCertificate(String key) { public String getUserCertificate(String key) { return mServiceCommand.execute( return ""; GET_USER_CERTIFICATE + COMMAND_DELIMITER + key); } } @Override @Override public String getCaCertificate(String key) { public String getCaCertificate(String key) { return mServiceCommand.execute( return ""; GET_CA_CERTIFICATE + COMMAND_DELIMITER + key); } } @Override @Override public String[] getAllUserCertificateKeys() { public String[] getAllUserCertificateKeys() { try { return new String[0]; String result = mServiceCommand.execute(LIST_USER_CERTIFICATES); if (result != null) return result.split("\\s+"); return NOTFOUND; } catch (NumberFormatException ex) { return NOTFOUND; } } } @Override @Override public String[] getAllCaCertificateKeys() { public String[] getAllCaCertificateKeys() { try { return new String[0]; String result = mServiceCommand.execute(LIST_CA_CERTIFICATES); if (result != null) return result.split("\\s+"); return NOTFOUND; } catch (NumberFormatException ex) { return NOTFOUND; } } } @Override @Override Loading Loading @@ -221,25 +155,77 @@ public abstract class Keystore { // TODO: real implementation // TODO: real implementation } } private boolean addUserCertificate(String key, String certificate, // to here String privateKey) { if(mServiceCommand.execute(ADD_USER_CERTIFICATE + COMMAND_DELIMITER @Override + key + COMMAND_DELIMITER + certificate) != null) { public int lock() { if (mServiceCommand.execute(ADD_USER_KEY + COMMAND_DELIMITER Reply result = mServiceCommand.execute(ServiceCommand.LOCK, null); + key + COMMAND_DELIMITER + privateKey) != null) { return (result != null) ? result.returnCode : -1; return true; } } @Override public int unlock(String password) { Reply result = mServiceCommand.execute(ServiceCommand.UNLOCK, password); return (result != null) ? result.returnCode : -1; } } return false; @Override public int getState() { Reply result = mServiceCommand.execute(ServiceCommand.GET_STATE, null); return (result != null) ? result.returnCode : -1; } } private boolean addCaCertificate(String key, String content) { @Override if (mServiceCommand.execute(ADD_CA_CERTIFICATE + COMMAND_DELIMITER public int changePassword(String oldPassword, String newPassword) { + key + COMMAND_DELIMITER + content) != null) { Reply result = mServiceCommand.execute(ServiceCommand.PASSWD, return true; oldPassword + " " + newPassword); return (result != null) ? result.returnCode : -1; } } return false; @Override public int setPassword(String firstPassword) { Reply result = mServiceCommand.execute(ServiceCommand.PASSWD, firstPassword); return (result != null) ? result.returnCode : -1; } } @Override public String[] listKeys(String namespace) { Reply result = mServiceCommand.execute(ServiceCommand.LIST_KEYS, namespace); return (result != null) ? ((result.returnCode != 0) ? NOTFOUND : new String(result.data, 0, result.len).split("\\s+")) : NOTFOUND; } @Override public int put(String namespace, String keyname, String value) { Reply result = mServiceCommand.execute(ServiceCommand.PUT_KEY, namespace + " " + keyname + " " + value); return (result != null) ? result.returnCode : -1; } @Override public String get(String namespace, String keyname) { Reply result = mServiceCommand.execute(ServiceCommand.GET_KEY, namespace + " " + keyname); return (result != null) ? ((result.returnCode != 0) ? null : new String(result.data, 0, result.len)) : null; } @Override public int remove(String namespace, String keyname) { Reply result = mServiceCommand.execute(ServiceCommand.REMOVE_KEY, namespace + " " + keyname); return (result != null) ? result.returnCode : -1; } @Override public int reset() { Reply result = mServiceCommand.execute(ServiceCommand.RESET, null); return (result != null) ? result.returnCode : -1; } } } } }
keystore/java/android/security/Reply.java 0 → 100644 +26 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2009 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; /* * {@hide} */ public class Reply { public int len; public int returnCode; public byte[] data = new byte[ServiceCommand.BUFFER_LENGTH]; }
keystore/java/android/security/ServiceCommand.java +53 −35 Original line number Original line Diff line number Diff line Loading @@ -35,15 +35,25 @@ public class ServiceCommand { public static final String SUCCESS = "0"; public static final String SUCCESS = "0"; public static final String FAILED = "-1"; public static final String FAILED = "-1"; // Opcodes for keystore commands. public static final int LOCK = 0; public static final int UNLOCK = 1; public static final int PASSWD = 2; public static final int GET_STATE = 3; public static final int LIST_KEYS = 4; public static final int GET_KEY = 5; public static final int PUT_KEY = 6; public static final int REMOVE_KEY = 7; public static final int RESET = 8; public static final int MAX_CMD_INDEX = 9; public static final int BUFFER_LENGTH = 4096; private String mServiceName; private String mServiceName; private String mTag; private String mTag; private InputStream mIn; private InputStream mIn; private OutputStream mOut; private OutputStream mOut; private LocalSocket mSocket; private LocalSocket mSocket; private static final int BUFFER_LENGTH = 1024; private byte buf[] = new byte[BUFFER_LENGTH]; private int buflen = 0; private boolean connect() { private boolean connect() { if (mSocket != null) { if (mSocket != null) { Loading Loading @@ -104,35 +114,47 @@ public class ServiceCommand { return false; return false; } } private boolean readReply() { private Reply readReply() { int len, ret; byte buf[] = new byte[4]; buflen = 0; Reply reply = new Reply(); if (!readBytes(buf, 2)) return false; if (!readBytes(buf, 4)) return null; ret = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8); reply.len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8) | if (ret != 0) return false; ((((int) buf[2]) & 0xff) << 16) | ((((int) buf[3]) & 0xff) << 24); if (!readBytes(buf, 2)) return false; if (!readBytes(buf, 4)) return null; len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8); reply.returnCode = (((int) buf[0]) & 0xff) | if (len > BUFFER_LENGTH) { ((((int) buf[1]) & 0xff) << 8) | Log.e(mTag,"invalid reply length (" + len + ")"); ((((int) buf[2]) & 0xff) << 16) | ((((int) buf[3]) & 0xff) << 24); if (reply.len > BUFFER_LENGTH) { Log.e(mTag,"invalid reply length (" + reply.len + ")"); disconnect(); disconnect(); return false; return null; } } if (!readBytes(buf, len)) return false; if (!readBytes(reply.data, reply.len)) return null; buflen = len; return reply; return true; } } private boolean writeCommand(String _cmd) { private boolean writeCommand(int cmd, String _data) { byte[] cmd = _cmd.getBytes(); byte buf[] = new byte[8]; int len = cmd.length; byte[] data = _data.getBytes(); if ((len < 1) || (len > BUFFER_LENGTH)) return false; int len = data.length; // the length of data buf[0] = (byte) (len & 0xff); buf[0] = (byte) (len & 0xff); buf[1] = (byte) ((len >> 8) & 0xff); buf[1] = (byte) ((len >> 8) & 0xff); buf[2] = (byte) ((len >> 16) & 0xff); buf[3] = (byte) ((len >> 24) & 0xff); // the opcode of the command buf[4] = (byte) (cmd & 0xff); buf[5] = (byte) ((cmd >> 8) & 0xff); buf[6] = (byte) ((cmd >> 16) & 0xff); buf[7] = (byte) ((cmd >> 24) & 0xff); try { try { mOut.write(buf, 0, 2); mOut.write(buf, 0, 8); mOut.write(cmd, 0, len); mOut.write(data, 0, len); } catch (IOException ex) { } catch (IOException ex) { Log.e(mTag,"write error"); Log.e(mTag,"write error"); disconnect(); disconnect(); Loading @@ -141,32 +163,28 @@ public class ServiceCommand { return true; return true; } } private String executeCommand(String cmd) { private Reply executeCommand(int cmd, String data) { if (!writeCommand(cmd)) { if (!writeCommand(cmd, data)) { /* If service died and restarted in the background /* If service died and restarted in the background * (unlikely but possible) we'll fail on the next * (unlikely but possible) we'll fail on the next * write (this one). Try to reconnect and write * write (this one). Try to reconnect and write * the command one more time before giving up. * the command one more time before giving up. */ */ Log.e(mTag, "write command failed? reconnect!"); Log.e(mTag, "write command failed? reconnect!"); if (!connect() || !writeCommand(cmd)) { if (!connect() || !writeCommand(cmd, data)) { return null; return null; } } } } if (readReply()) { return readReply(); return new String(buf, 0, buflen); } else { return null; } } } public synchronized String execute(String cmd) { public synchronized Reply execute(int cmd, String data) { String result; Reply result; if (!connect()) { if (!connect()) { Log.e(mTag, "connection failed"); Log.e(mTag, "connection failed"); return null; return null; } } result = executeCommand(cmd); result = executeCommand(cmd, data); disconnect(); disconnect(); return result; return result; } } Loading
keystore/jni/Android.mk 0 → 100644 +31 −0 Original line number Original line Diff line number Diff line LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ cert.c certtool.c LOCAL_C_INCLUDES += \ $(JNI_H_INCLUDE) \ external/openssl/include LOCAL_SHARED_LIBRARIES := \ libcutils \ libnativehelper \ libutils \ libcrypto ifeq ($(TARGET_SIMULATOR),true) ifeq ($(TARGET_OS),linux) ifeq ($(TARGET_ARCH),x86) LOCAL_LDLIBS += -lpthread -ldl -lrt -lssl endif endif endif ifeq ($(WITH_MALLOC_LEAK_CHECK),true) LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK endif LOCAL_MODULE:= libcerttool_jni include $(BUILD_SHARED_LIBRARY)