Merge "Switch keystore to binder"
This commit is contained in:
@@ -47,6 +47,7 @@ static struct {
|
||||
{ AID_RADIO, "simphonebook" },
|
||||
{ AID_MEDIA, "common_time.clock" },
|
||||
{ AID_MEDIA, "common_time.config" },
|
||||
{ AID_KEYSTORE, "android.security.keystore" },
|
||||
};
|
||||
|
||||
void *svcmgr_handle;
|
||||
|
||||
505
core/java/android/security/IKeystoreService.java
Normal file
505
core/java/android/security/IKeystoreService.java
Normal file
@@ -0,0 +1,505 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.IInterface;
|
||||
import android.os.Parcel;
|
||||
import android.os.RemoteException;
|
||||
|
||||
/**
|
||||
* This must be kept manually in sync with system/security/keystore until AIDL
|
||||
* can generate both Java and C++ bindings.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public interface IKeystoreService extends IInterface {
|
||||
public static abstract class Stub extends Binder implements IKeystoreService {
|
||||
private static class Proxy implements IKeystoreService {
|
||||
private final IBinder mRemote;
|
||||
|
||||
Proxy(IBinder remote) {
|
||||
mRemote = remote;
|
||||
}
|
||||
|
||||
public IBinder asBinder() {
|
||||
return mRemote;
|
||||
}
|
||||
|
||||
public String getInterfaceDescriptor() {
|
||||
return DESCRIPTOR;
|
||||
}
|
||||
|
||||
public int test() throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
int _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
mRemote.transact(Stub.TRANSACTION_test, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.readInt();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
public byte[] get(String name) throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
byte[] _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
_data.writeString(name);
|
||||
mRemote.transact(Stub.TRANSACTION_get, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.createByteArray();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
public int insert(String name, byte[] item) throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
int _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
_data.writeString(name);
|
||||
_data.writeByteArray(item);
|
||||
mRemote.transact(Stub.TRANSACTION_insert, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.readInt();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
public int del(String name) throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
int _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
_data.writeString(name);
|
||||
mRemote.transact(Stub.TRANSACTION_del, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.readInt();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
public int exist(String name) throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
int _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
_data.writeString(name);
|
||||
mRemote.transact(Stub.TRANSACTION_exist, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.readInt();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
public String[] saw(String name) throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
String[] _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
_data.writeString(name);
|
||||
mRemote.transact(Stub.TRANSACTION_saw, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
int size = _reply.readInt();
|
||||
_result = new String[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
_result[i] = _reply.readString();
|
||||
}
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int reset() throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
int _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
mRemote.transact(Stub.TRANSACTION_reset, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.readInt();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
public int password(String password) throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
int _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
_data.writeString(password);
|
||||
mRemote.transact(Stub.TRANSACTION_password, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.readInt();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
public int lock() throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
int _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
mRemote.transact(Stub.TRANSACTION_lock, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.readInt();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
public int unlock(String password) throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
int _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
_data.writeString(password);
|
||||
mRemote.transact(Stub.TRANSACTION_unlock, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.readInt();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int zero() throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
int _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
mRemote.transact(Stub.TRANSACTION_zero, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.readInt();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
public int generate(String name) throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
int _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
_data.writeString(name);
|
||||
mRemote.transact(Stub.TRANSACTION_generate, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.readInt();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
public int import_key(String name, byte[] data) throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
int _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
_data.writeString(name);
|
||||
_data.writeByteArray(data);
|
||||
mRemote.transact(Stub.TRANSACTION_import, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.readInt();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
public byte[] sign(String name, byte[] data) throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
byte[] _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
_data.writeString(name);
|
||||
_data.writeByteArray(data);
|
||||
mRemote.transact(Stub.TRANSACTION_sign, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.createByteArray();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
public int verify(String name, byte[] data, byte[] signature) throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
int _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
_data.writeString(name);
|
||||
_data.writeByteArray(data);
|
||||
_data.writeByteArray(signature);
|
||||
mRemote.transact(Stub.TRANSACTION_verify, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.readInt();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
public byte[] get_pubkey(String name) throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
byte[] _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
_data.writeString(name);
|
||||
mRemote.transact(Stub.TRANSACTION_get_pubkey, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.createByteArray();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
public int del_key(String name) throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
int _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
_data.writeString(name);
|
||||
mRemote.transact(Stub.TRANSACTION_del_key, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.readInt();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
public int grant(String name, int granteeUid) throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
int _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
_data.writeString(name);
|
||||
_data.writeInt(granteeUid);
|
||||
mRemote.transact(Stub.TRANSACTION_grant, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.readInt();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
public int ungrant(String name, int granteeUid) throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
int _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
_data.writeString(name);
|
||||
_data.writeInt(granteeUid);
|
||||
mRemote.transact(Stub.TRANSACTION_ungrant, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.readInt();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getmtime(String name) throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
long _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
_data.writeString(name);
|
||||
mRemote.transact(Stub.TRANSACTION_getmtime, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.readLong();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String DESCRIPTOR = "android.security.keystore";
|
||||
|
||||
static final int TRANSACTION_test = IBinder.FIRST_CALL_TRANSACTION + 0;
|
||||
static final int TRANSACTION_get = IBinder.FIRST_CALL_TRANSACTION + 1;
|
||||
static final int TRANSACTION_insert = IBinder.FIRST_CALL_TRANSACTION + 2;
|
||||
static final int TRANSACTION_del = IBinder.FIRST_CALL_TRANSACTION + 3;
|
||||
static final int TRANSACTION_exist = IBinder.FIRST_CALL_TRANSACTION + 4;
|
||||
static final int TRANSACTION_saw = IBinder.FIRST_CALL_TRANSACTION + 5;
|
||||
static final int TRANSACTION_reset = IBinder.FIRST_CALL_TRANSACTION + 6;
|
||||
static final int TRANSACTION_password = IBinder.FIRST_CALL_TRANSACTION + 7;
|
||||
static final int TRANSACTION_lock = IBinder.FIRST_CALL_TRANSACTION + 8;
|
||||
static final int TRANSACTION_unlock = IBinder.FIRST_CALL_TRANSACTION + 9;
|
||||
static final int TRANSACTION_zero = IBinder.FIRST_CALL_TRANSACTION + 10;
|
||||
static final int TRANSACTION_generate = IBinder.FIRST_CALL_TRANSACTION + 11;
|
||||
static final int TRANSACTION_import = IBinder.FIRST_CALL_TRANSACTION + 12;
|
||||
static final int TRANSACTION_sign = IBinder.FIRST_CALL_TRANSACTION + 13;
|
||||
static final int TRANSACTION_verify = IBinder.FIRST_CALL_TRANSACTION + 14;
|
||||
static final int TRANSACTION_get_pubkey = IBinder.FIRST_CALL_TRANSACTION + 15;
|
||||
static final int TRANSACTION_del_key = IBinder.FIRST_CALL_TRANSACTION + 16;
|
||||
static final int TRANSACTION_grant = IBinder.FIRST_CALL_TRANSACTION + 17;
|
||||
static final int TRANSACTION_ungrant = IBinder.FIRST_CALL_TRANSACTION + 18;
|
||||
static final int TRANSACTION_getmtime = IBinder.FIRST_CALL_TRANSACTION + 19;
|
||||
|
||||
/**
|
||||
* Cast an IBinder object into an IKeystoreService interface, generating
|
||||
* a proxy if needed.
|
||||
*/
|
||||
public static IKeystoreService asInterface(IBinder obj) {
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
|
||||
if (iin != null && iin instanceof IKeystoreService) {
|
||||
return (IKeystoreService) iin;
|
||||
}
|
||||
return new IKeystoreService.Stub.Proxy(obj);
|
||||
}
|
||||
|
||||
/** Construct the stub at attach it to the interface. */
|
||||
public Stub() {
|
||||
attachInterface(this, DESCRIPTOR);
|
||||
}
|
||||
|
||||
public IBinder asBinder() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
|
||||
throws RemoteException {
|
||||
switch (code) {
|
||||
case INTERFACE_TRANSACTION: {
|
||||
reply.writeString(DESCRIPTOR);
|
||||
return true;
|
||||
}
|
||||
case TRANSACTION_test: {
|
||||
data.enforceInterface(DESCRIPTOR);
|
||||
int resultCode = test();
|
||||
reply.writeNoException();
|
||||
reply.writeInt(resultCode);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onTransact(code, data, reply, flags);
|
||||
}
|
||||
}
|
||||
|
||||
public int test() throws RemoteException;
|
||||
|
||||
public byte[] get(String name) throws RemoteException;
|
||||
|
||||
public int insert(String name, byte[] item) throws RemoteException;
|
||||
|
||||
public int del(String name) throws RemoteException;
|
||||
|
||||
public int exist(String name) throws RemoteException;
|
||||
|
||||
public String[] saw(String name) throws RemoteException;
|
||||
|
||||
public int reset() throws RemoteException;
|
||||
|
||||
public int password(String password) throws RemoteException;
|
||||
|
||||
public int lock() throws RemoteException;
|
||||
|
||||
public int unlock(String password) throws RemoteException;
|
||||
|
||||
public int zero() throws RemoteException;
|
||||
|
||||
public int generate(String name) throws RemoteException;
|
||||
|
||||
public int import_key(String name, byte[] data) throws RemoteException;
|
||||
|
||||
public byte[] sign(String name, byte[] data) throws RemoteException;
|
||||
|
||||
public int verify(String name, byte[] data, byte[] signature) throws RemoteException;
|
||||
|
||||
public byte[] get_pubkey(String name) throws RemoteException;
|
||||
|
||||
public int del_key(String name) throws RemoteException;
|
||||
|
||||
public int grant(String name, int granteeUid) throws RemoteException;
|
||||
|
||||
public int ungrant(String name, int granteeUid) throws RemoteException;
|
||||
|
||||
public long getmtime(String name) throws RemoteException;
|
||||
}
|
||||
@@ -16,17 +16,9 @@
|
||||
|
||||
package android.security;
|
||||
|
||||
import android.net.LocalSocketAddress;
|
||||
import android.net.LocalSocket;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UTFDataFormatException;
|
||||
import java.nio.charset.Charsets;
|
||||
import java.nio.charset.ModifiedUtf8;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* @hide This should not be made public in its present form because it
|
||||
@@ -34,6 +26,7 @@ import java.util.Date;
|
||||
* preclude the use of hardware crypto.
|
||||
*/
|
||||
public class KeyStore {
|
||||
private static final String TAG = "KeyStore";
|
||||
|
||||
// ResponseCodes
|
||||
public static final int NO_ERROR = 1;
|
||||
@@ -50,20 +43,30 @@ public class KeyStore {
|
||||
// States
|
||||
public enum State { UNLOCKED, LOCKED, UNINITIALIZED };
|
||||
|
||||
private static final LocalSocketAddress sAddress = new LocalSocketAddress(
|
||||
"keystore", LocalSocketAddress.Namespace.RESERVED);
|
||||
|
||||
private int mError = NO_ERROR;
|
||||
|
||||
private KeyStore() {}
|
||||
private final IKeystoreService mBinder;
|
||||
|
||||
private KeyStore(IKeystoreService binder) {
|
||||
mBinder = binder;
|
||||
}
|
||||
|
||||
public static KeyStore getInstance() {
|
||||
return new KeyStore();
|
||||
IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager
|
||||
.getService("android.security.keystore"));
|
||||
return new KeyStore(keystore);
|
||||
}
|
||||
|
||||
public State state() {
|
||||
execute('t');
|
||||
switch (mError) {
|
||||
final int ret;
|
||||
try {
|
||||
ret = mBinder.test();
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
switch (ret) {
|
||||
case NO_ERROR: return State.UNLOCKED;
|
||||
case LOCKED: return State.LOCKED;
|
||||
case UNINITIALIZED: return State.UNINITIALIZED;
|
||||
@@ -71,171 +74,167 @@ public class KeyStore {
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] get(byte[] key) {
|
||||
ArrayList<byte[]> values = execute('g', key);
|
||||
return (values == null || values.isEmpty()) ? null : values.get(0);
|
||||
}
|
||||
|
||||
public byte[] get(String key) {
|
||||
return get(getKeyBytes(key));
|
||||
}
|
||||
|
||||
private boolean put(byte[] key, byte[] value) {
|
||||
execute('i', key, value);
|
||||
return mError == NO_ERROR;
|
||||
try {
|
||||
return mBinder.get(key);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean put(String key, byte[] value) {
|
||||
return put(getKeyBytes(key), value);
|
||||
}
|
||||
|
||||
private boolean delete(byte[] key) {
|
||||
execute('d', key);
|
||||
return mError == NO_ERROR;
|
||||
try {
|
||||
return mBinder.insert(key, value) == NO_ERROR;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean delete(String key) {
|
||||
return delete(getKeyBytes(key));
|
||||
}
|
||||
|
||||
private boolean contains(byte[] key) {
|
||||
execute('e', key);
|
||||
return mError == NO_ERROR;
|
||||
try {
|
||||
return mBinder.del(key) == NO_ERROR;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(String key) {
|
||||
return contains(getKeyBytes(key));
|
||||
}
|
||||
|
||||
public byte[][] saw(byte[] prefix) {
|
||||
ArrayList<byte[]> values = execute('s', prefix);
|
||||
return (values == null) ? null : values.toArray(new byte[values.size()][]);
|
||||
try {
|
||||
return mBinder.exist(key) == NO_ERROR;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String[] saw(String prefix) {
|
||||
byte[][] values = saw(getKeyBytes(prefix));
|
||||
if (values == null) {
|
||||
try {
|
||||
return mBinder.saw(prefix);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return null;
|
||||
}
|
||||
String[] strings = new String[values.length];
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
strings[i] = toKeyString(values[i]);
|
||||
}
|
||||
return strings;
|
||||
}
|
||||
|
||||
public boolean reset() {
|
||||
execute('r');
|
||||
return mError == NO_ERROR;
|
||||
}
|
||||
|
||||
private boolean password(byte[] password) {
|
||||
execute('p', password);
|
||||
return mError == NO_ERROR;
|
||||
try {
|
||||
return mBinder.reset() == NO_ERROR;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean password(String password) {
|
||||
return password(getPasswordBytes(password));
|
||||
try {
|
||||
return mBinder.password(password) == NO_ERROR;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean lock() {
|
||||
execute('l');
|
||||
return mError == NO_ERROR;
|
||||
}
|
||||
|
||||
private boolean unlock(byte[] password) {
|
||||
execute('u', password);
|
||||
return mError == NO_ERROR;
|
||||
try {
|
||||
return mBinder.lock() == NO_ERROR;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean unlock(String password) {
|
||||
return unlock(getPasswordBytes(password));
|
||||
try {
|
||||
mError = mBinder.unlock(password);
|
||||
return mError == NO_ERROR;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
execute('z');
|
||||
return mError == KEY_NOT_FOUND;
|
||||
}
|
||||
|
||||
private boolean generate(byte[] key) {
|
||||
execute('a', key);
|
||||
return mError == NO_ERROR;
|
||||
try {
|
||||
return mBinder.zero() == KEY_NOT_FOUND;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean generate(String key) {
|
||||
return generate(getKeyBytes(key));
|
||||
}
|
||||
|
||||
private boolean importKey(byte[] keyName, byte[] key) {
|
||||
execute('m', keyName, key);
|
||||
return mError == NO_ERROR;
|
||||
try {
|
||||
return mBinder.generate(key) == NO_ERROR;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean importKey(String keyName, byte[] key) {
|
||||
return importKey(getKeyBytes(keyName), key);
|
||||
}
|
||||
|
||||
private byte[] getPubkey(byte[] key) {
|
||||
ArrayList<byte[]> values = execute('b', key);
|
||||
return (values == null || values.isEmpty()) ? null : values.get(0);
|
||||
try {
|
||||
return mBinder.import_key(keyName, key) == NO_ERROR;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getPubkey(String key) {
|
||||
return getPubkey(getKeyBytes(key));
|
||||
}
|
||||
|
||||
private boolean delKey(byte[] key) {
|
||||
execute('k', key);
|
||||
return mError == NO_ERROR;
|
||||
try {
|
||||
return mBinder.get_pubkey(key);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean delKey(String key) {
|
||||
return delKey(getKeyBytes(key));
|
||||
}
|
||||
|
||||
private byte[] sign(byte[] keyName, byte[] data) {
|
||||
final ArrayList<byte[]> values = execute('n', keyName, data);
|
||||
return (values == null || values.isEmpty()) ? null : values.get(0);
|
||||
try {
|
||||
return mBinder.del_key(key) == NO_ERROR;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] sign(String key, byte[] data) {
|
||||
return sign(getKeyBytes(key), data);
|
||||
}
|
||||
|
||||
private boolean verify(byte[] keyName, byte[] data, byte[] signature) {
|
||||
execute('v', keyName, data, signature);
|
||||
return mError == NO_ERROR;
|
||||
try {
|
||||
return mBinder.sign(key, data);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean verify(String key, byte[] data, byte[] signature) {
|
||||
return verify(getKeyBytes(key), data, signature);
|
||||
}
|
||||
|
||||
private boolean grant(byte[] key, byte[] uid) {
|
||||
execute('x', key, uid);
|
||||
return mError == NO_ERROR;
|
||||
try {
|
||||
return mBinder.verify(key, data, signature) == NO_ERROR;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean grant(String key, int uid) {
|
||||
return grant(getKeyBytes(key), getUidBytes(uid));
|
||||
}
|
||||
|
||||
private boolean ungrant(byte[] key, byte[] uid) {
|
||||
execute('y', key, uid);
|
||||
return mError == NO_ERROR;
|
||||
try {
|
||||
return mBinder.grant(key, uid) == NO_ERROR;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean ungrant(String key, int uid) {
|
||||
return ungrant(getKeyBytes(key), getUidBytes(uid));
|
||||
}
|
||||
|
||||
private long getmtime(byte[] key) {
|
||||
final ArrayList<byte[]> values = execute('c', key);
|
||||
if (values == null || values.isEmpty()) {
|
||||
return -1L;
|
||||
try {
|
||||
return mBinder.ungrant(key, uid) == NO_ERROR;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return Long.parseLong(new String(values.get(0))) * 1000L;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,101 +242,15 @@ public class KeyStore {
|
||||
* epoch. Will return -1L if the key could not be found or other error.
|
||||
*/
|
||||
public long getmtime(String key) {
|
||||
return getmtime(getKeyBytes(key));
|
||||
try {
|
||||
return mBinder.getmtime(key);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Cannot connect to keystore", e);
|
||||
return -1L;
|
||||
}
|
||||
}
|
||||
|
||||
public int getLastError() {
|
||||
return mError;
|
||||
}
|
||||
|
||||
private ArrayList<byte[]> execute(int code, byte[]... parameters) {
|
||||
mError = PROTOCOL_ERROR;
|
||||
|
||||
for (byte[] parameter : parameters) {
|
||||
if (parameter == null || parameter.length > 65535) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
LocalSocket socket = new LocalSocket();
|
||||
try {
|
||||
socket.connect(sAddress);
|
||||
|
||||
OutputStream out = socket.getOutputStream();
|
||||
out.write(code);
|
||||
for (byte[] parameter : parameters) {
|
||||
out.write(parameter.length >> 8);
|
||||
out.write(parameter.length);
|
||||
out.write(parameter);
|
||||
}
|
||||
out.flush();
|
||||
socket.shutdownOutput();
|
||||
|
||||
InputStream in = socket.getInputStream();
|
||||
if ((code = in.read()) != NO_ERROR) {
|
||||
if (code != -1) {
|
||||
mError = code;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<byte[]> values = new ArrayList<byte[]>();
|
||||
while (true) {
|
||||
int i, j;
|
||||
if ((i = in.read()) == -1) {
|
||||
break;
|
||||
}
|
||||
if ((j = in.read()) == -1) {
|
||||
return null;
|
||||
}
|
||||
byte[] value = new byte[i << 8 | j];
|
||||
for (i = 0; i < value.length; i += j) {
|
||||
if ((j = in.read(value, i, value.length - i)) == -1) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
values.add(value);
|
||||
}
|
||||
mError = NO_ERROR;
|
||||
return values;
|
||||
} catch (IOException e) {
|
||||
// ignore
|
||||
} finally {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* ModifiedUtf8 is used for key encoding to match the
|
||||
* implementation of NativeCrypto.ENGINE_load_private_key.
|
||||
*/
|
||||
private static byte[] getKeyBytes(String string) {
|
||||
try {
|
||||
int utfCount = (int) ModifiedUtf8.countBytes(string, false);
|
||||
byte[] result = new byte[utfCount];
|
||||
ModifiedUtf8.encode(result, 0, string);
|
||||
return result;
|
||||
} catch (UTFDataFormatException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String toKeyString(byte[] bytes) {
|
||||
try {
|
||||
return ModifiedUtf8.decode(bytes, new char[bytes.length], 0, bytes.length);
|
||||
} catch (UTFDataFormatException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] getPasswordBytes(String password) {
|
||||
return password.getBytes(Charsets.UTF_8);
|
||||
}
|
||||
|
||||
private static byte[] getUidBytes(int uid) {
|
||||
return Integer.toString(uid).getBytes(Charsets.UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user