Loading keystore/java/android/security/CertTool.java 0 → 100644 +143 −0 Original line number 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 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. * {@hide} */ public abstract class Keystore { private static final String TAG = "Keystore"; private static final String[] NOTFOUND = new String[0]; Loading @@ -30,25 +31,18 @@ public abstract class Keystore { return new FileKeystore(); } // for compatiblity, start from here /** */ public abstract String getUserkey(String key); /** */ public abstract String getCertificate(String key); /** */ public abstract String[] getAllCertificateKeys(); /** */ public abstract String[] getAllUserkeyKeys(); // to here public abstract int lock(); public abstract int unlock(String password); public abstract int getState(); 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 get(String namespace, String keyname); public abstract int remove(String namespace, String keyname); public abstract int reset(); // TODO: for migrating to the mini-keystore, clean up from here /** */ public abstract String getCaCertificate(String key); Loading Loading @@ -89,101 +83,41 @@ public abstract class Keystore { int keyStrengthIndex, String challenge, String organizations); public abstract void addCertificate(byte[] cert); // to here private static class FileKeystore extends Keystore { private static final String SERVICE_NAME = "keystore"; private static final String LIST_CA_CERTIFICATES = "listcacerts"; private static final String LIST_USER_CERTIFICATES = "listusercerts"; private static final String GET_CA_CERTIFICATE = "getcacert"; private static final String GET_USER_CERTIFICATE = "getusercert"; 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 String CA_CERTIFICATE = "CaCertificate"; private static final String USER_CERTIFICATE = "UserCertificate"; private static final String USER_KEY = "UserPrivateKey"; private static final String COMMAND_DELIMITER = " "; private static final ServiceCommand mServiceCommand = new ServiceCommand(SERVICE_NAME); // for compatiblity, 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 // TODO: for migrating to the mini-keystore, start from here @Override public String getUserPrivateKey(String key) { return mServiceCommand.execute( GET_USER_KEY + COMMAND_DELIMITER + key); return ""; } @Override public String getUserCertificate(String key) { return mServiceCommand.execute( GET_USER_CERTIFICATE + COMMAND_DELIMITER + key); return ""; } @Override public String getCaCertificate(String key) { return mServiceCommand.execute( GET_CA_CERTIFICATE + COMMAND_DELIMITER + key); return ""; } @Override public String[] getAllUserCertificateKeys() { try { String result = mServiceCommand.execute(LIST_USER_CERTIFICATES); if (result != null) return result.split("\\s+"); return NOTFOUND; } catch (NumberFormatException ex) { return NOTFOUND; } return new String[0]; } @Override public String[] getAllCaCertificateKeys() { try { String result = mServiceCommand.execute(LIST_CA_CERTIFICATES); if (result != null) return result.split("\\s+"); return NOTFOUND; } catch (NumberFormatException ex) { return NOTFOUND; } return new String[0]; } @Override Loading Loading @@ -221,25 +155,77 @@ public abstract class Keystore { // TODO: real implementation } private boolean addUserCertificate(String key, String certificate, String privateKey) { if(mServiceCommand.execute(ADD_USER_CERTIFICATE + COMMAND_DELIMITER + key + COMMAND_DELIMITER + certificate) != null) { if (mServiceCommand.execute(ADD_USER_KEY + COMMAND_DELIMITER + key + COMMAND_DELIMITER + privateKey) != null) { return true; // to here @Override public int lock() { Reply result = mServiceCommand.execute(ServiceCommand.LOCK, null); return (result != null) ? result.returnCode : -1; } @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) { if (mServiceCommand.execute(ADD_CA_CERTIFICATE + COMMAND_DELIMITER + key + COMMAND_DELIMITER + content) != null) { return true; @Override public int changePassword(String oldPassword, String newPassword) { Reply result = mServiceCommand.execute(ServiceCommand.PASSWD, 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 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 Diff line number Diff line Loading @@ -35,15 +35,25 @@ public class ServiceCommand { public static final String SUCCESS = "0"; 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 mTag; private InputStream mIn; private OutputStream mOut; private LocalSocket mSocket; private static final int BUFFER_LENGTH = 1024; private byte buf[] = new byte[BUFFER_LENGTH]; private int buflen = 0; private boolean connect() { if (mSocket != null) { Loading Loading @@ -104,35 +114,47 @@ public class ServiceCommand { return false; } private boolean readReply() { int len, ret; buflen = 0; private Reply readReply() { byte buf[] = new byte[4]; Reply reply = new Reply(); if (!readBytes(buf, 2)) return false; ret = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8); if (ret != 0) return false; if (!readBytes(buf, 4)) return null; reply.len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8) | ((((int) buf[2]) & 0xff) << 16) | ((((int) buf[3]) & 0xff) << 24); if (!readBytes(buf, 2)) return false; len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8); if (len > BUFFER_LENGTH) { Log.e(mTag,"invalid reply length (" + len + ")"); if (!readBytes(buf, 4)) return null; reply.returnCode = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8) | ((((int) buf[2]) & 0xff) << 16) | ((((int) buf[3]) & 0xff) << 24); if (reply.len > BUFFER_LENGTH) { Log.e(mTag,"invalid reply length (" + reply.len + ")"); disconnect(); return false; return null; } if (!readBytes(buf, len)) return false; buflen = len; return true; if (!readBytes(reply.data, reply.len)) return null; return reply; } private boolean writeCommand(String _cmd) { byte[] cmd = _cmd.getBytes(); int len = cmd.length; if ((len < 1) || (len > BUFFER_LENGTH)) return false; private boolean writeCommand(int cmd, String _data) { byte buf[] = new byte[8]; byte[] data = _data.getBytes(); int len = data.length; // the length of data buf[0] = (byte) (len & 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 { mOut.write(buf, 0, 2); mOut.write(cmd, 0, len); mOut.write(buf, 0, 8); mOut.write(data, 0, len); } catch (IOException ex) { Log.e(mTag,"write error"); disconnect(); Loading @@ -141,32 +163,28 @@ public class ServiceCommand { return true; } private String executeCommand(String cmd) { if (!writeCommand(cmd)) { private Reply executeCommand(int cmd, String data) { if (!writeCommand(cmd, data)) { /* If service died and restarted in the background * (unlikely but possible) we'll fail on the next * write (this one). Try to reconnect and write * the command one more time before giving up. */ Log.e(mTag, "write command failed? reconnect!"); if (!connect() || !writeCommand(cmd)) { if (!connect() || !writeCommand(cmd, data)) { return null; } } if (readReply()) { return new String(buf, 0, buflen); } else { return null; } return readReply(); } public synchronized String execute(String cmd) { String result; public synchronized Reply execute(int cmd, String data) { Reply result; if (!connect()) { Log.e(mTag, "connection failed"); return null; } result = executeCommand(cmd); result = executeCommand(cmd, data); disconnect(); return result; } Loading keystore/jni/Android.mk 0 → 100644 +31 −0 Original line number 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 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 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. * {@hide} */ public abstract class Keystore { private static final String TAG = "Keystore"; private static final String[] NOTFOUND = new String[0]; Loading @@ -30,25 +31,18 @@ public abstract class Keystore { return new FileKeystore(); } // for compatiblity, start from here /** */ public abstract String getUserkey(String key); /** */ public abstract String getCertificate(String key); /** */ public abstract String[] getAllCertificateKeys(); /** */ public abstract String[] getAllUserkeyKeys(); // to here public abstract int lock(); public abstract int unlock(String password); public abstract int getState(); 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 get(String namespace, String keyname); public abstract int remove(String namespace, String keyname); public abstract int reset(); // TODO: for migrating to the mini-keystore, clean up from here /** */ public abstract String getCaCertificate(String key); Loading Loading @@ -89,101 +83,41 @@ public abstract class Keystore { int keyStrengthIndex, String challenge, String organizations); public abstract void addCertificate(byte[] cert); // to here private static class FileKeystore extends Keystore { private static final String SERVICE_NAME = "keystore"; private static final String LIST_CA_CERTIFICATES = "listcacerts"; private static final String LIST_USER_CERTIFICATES = "listusercerts"; private static final String GET_CA_CERTIFICATE = "getcacert"; private static final String GET_USER_CERTIFICATE = "getusercert"; 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 String CA_CERTIFICATE = "CaCertificate"; private static final String USER_CERTIFICATE = "UserCertificate"; private static final String USER_KEY = "UserPrivateKey"; private static final String COMMAND_DELIMITER = " "; private static final ServiceCommand mServiceCommand = new ServiceCommand(SERVICE_NAME); // for compatiblity, 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 // TODO: for migrating to the mini-keystore, start from here @Override public String getUserPrivateKey(String key) { return mServiceCommand.execute( GET_USER_KEY + COMMAND_DELIMITER + key); return ""; } @Override public String getUserCertificate(String key) { return mServiceCommand.execute( GET_USER_CERTIFICATE + COMMAND_DELIMITER + key); return ""; } @Override public String getCaCertificate(String key) { return mServiceCommand.execute( GET_CA_CERTIFICATE + COMMAND_DELIMITER + key); return ""; } @Override public String[] getAllUserCertificateKeys() { try { String result = mServiceCommand.execute(LIST_USER_CERTIFICATES); if (result != null) return result.split("\\s+"); return NOTFOUND; } catch (NumberFormatException ex) { return NOTFOUND; } return new String[0]; } @Override public String[] getAllCaCertificateKeys() { try { String result = mServiceCommand.execute(LIST_CA_CERTIFICATES); if (result != null) return result.split("\\s+"); return NOTFOUND; } catch (NumberFormatException ex) { return NOTFOUND; } return new String[0]; } @Override Loading Loading @@ -221,25 +155,77 @@ public abstract class Keystore { // TODO: real implementation } private boolean addUserCertificate(String key, String certificate, String privateKey) { if(mServiceCommand.execute(ADD_USER_CERTIFICATE + COMMAND_DELIMITER + key + COMMAND_DELIMITER + certificate) != null) { if (mServiceCommand.execute(ADD_USER_KEY + COMMAND_DELIMITER + key + COMMAND_DELIMITER + privateKey) != null) { return true; // to here @Override public int lock() { Reply result = mServiceCommand.execute(ServiceCommand.LOCK, null); return (result != null) ? result.returnCode : -1; } @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) { if (mServiceCommand.execute(ADD_CA_CERTIFICATE + COMMAND_DELIMITER + key + COMMAND_DELIMITER + content) != null) { return true; @Override public int changePassword(String oldPassword, String newPassword) { Reply result = mServiceCommand.execute(ServiceCommand.PASSWD, 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 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 Diff line number Diff line Loading @@ -35,15 +35,25 @@ public class ServiceCommand { public static final String SUCCESS = "0"; 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 mTag; private InputStream mIn; private OutputStream mOut; private LocalSocket mSocket; private static final int BUFFER_LENGTH = 1024; private byte buf[] = new byte[BUFFER_LENGTH]; private int buflen = 0; private boolean connect() { if (mSocket != null) { Loading Loading @@ -104,35 +114,47 @@ public class ServiceCommand { return false; } private boolean readReply() { int len, ret; buflen = 0; private Reply readReply() { byte buf[] = new byte[4]; Reply reply = new Reply(); if (!readBytes(buf, 2)) return false; ret = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8); if (ret != 0) return false; if (!readBytes(buf, 4)) return null; reply.len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8) | ((((int) buf[2]) & 0xff) << 16) | ((((int) buf[3]) & 0xff) << 24); if (!readBytes(buf, 2)) return false; len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8); if (len > BUFFER_LENGTH) { Log.e(mTag,"invalid reply length (" + len + ")"); if (!readBytes(buf, 4)) return null; reply.returnCode = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8) | ((((int) buf[2]) & 0xff) << 16) | ((((int) buf[3]) & 0xff) << 24); if (reply.len > BUFFER_LENGTH) { Log.e(mTag,"invalid reply length (" + reply.len + ")"); disconnect(); return false; return null; } if (!readBytes(buf, len)) return false; buflen = len; return true; if (!readBytes(reply.data, reply.len)) return null; return reply; } private boolean writeCommand(String _cmd) { byte[] cmd = _cmd.getBytes(); int len = cmd.length; if ((len < 1) || (len > BUFFER_LENGTH)) return false; private boolean writeCommand(int cmd, String _data) { byte buf[] = new byte[8]; byte[] data = _data.getBytes(); int len = data.length; // the length of data buf[0] = (byte) (len & 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 { mOut.write(buf, 0, 2); mOut.write(cmd, 0, len); mOut.write(buf, 0, 8); mOut.write(data, 0, len); } catch (IOException ex) { Log.e(mTag,"write error"); disconnect(); Loading @@ -141,32 +163,28 @@ public class ServiceCommand { return true; } private String executeCommand(String cmd) { if (!writeCommand(cmd)) { private Reply executeCommand(int cmd, String data) { if (!writeCommand(cmd, data)) { /* If service died and restarted in the background * (unlikely but possible) we'll fail on the next * write (this one). Try to reconnect and write * the command one more time before giving up. */ Log.e(mTag, "write command failed? reconnect!"); if (!connect() || !writeCommand(cmd)) { if (!connect() || !writeCommand(cmd, data)) { return null; } } if (readReply()) { return new String(buf, 0, buflen); } else { return null; } return readReply(); } public synchronized String execute(String cmd) { String result; public synchronized Reply execute(int cmd, String data) { Reply result; if (!connect()) { Log.e(mTag, "connection failed"); return null; } result = executeCommand(cmd); result = executeCommand(cmd, data); disconnect(); return result; } Loading
keystore/jni/Android.mk 0 → 100644 +31 −0 Original line number 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)