C++程序  |  1873行  |  65.66 KB

/*
**
** Copyright 2008, 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.
*/

#include <stdint.h>
#include <sys/limits.h>
#include <sys/types.h>

#define LOG_TAG "KeystoreService"
#include <utils/Log.h>

#include <binder/Parcel.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>

#include <keystore/IKeystoreService.h>

namespace android {

const ssize_t MAX_GENERATE_ARGS = 3;
static keymaster_key_param_t* readParamList(const Parcel& in, size_t* length);

KeystoreArg::KeystoreArg(const void* data, size_t len)
    : mData(data), mSize(len) {
}

KeystoreArg::~KeystoreArg() {
}

const void *KeystoreArg::data() const {
    return mData;
}

size_t KeystoreArg::size() const {
    return mSize;
}

OperationResult::OperationResult() : resultCode(0), token(), handle(0), inputConsumed(0),
    data(NULL), dataLength(0) {
}

OperationResult::~OperationResult() {
}

void OperationResult::readFromParcel(const Parcel& in) {
    resultCode = in.readInt32();
    token = in.readStrongBinder();
    handle = static_cast<keymaster_operation_handle_t>(in.readInt64());
    inputConsumed = in.readInt32();
    ssize_t length = in.readInt32();
    dataLength = 0;
    if (length > 0) {
        const void* buf = in.readInplace(length);
        if (buf) {
            data.reset(reinterpret_cast<uint8_t*>(malloc(length)));
            if (data.get()) {
                memcpy(data.get(), buf, length);
                dataLength = (size_t) length;
            } else {
                ALOGE("Failed to allocate OperationResult buffer");
            }
        } else {
            ALOGE("Failed to readInplace OperationResult data");
        }
    }
    outParams.readFromParcel(in);
}

void OperationResult::writeToParcel(Parcel* out) const {
    out->writeInt32(resultCode);
    out->writeStrongBinder(token);
    out->writeInt64(handle);
    out->writeInt32(inputConsumed);
    out->writeInt32(dataLength);
    if (dataLength && data) {
        void* buf = out->writeInplace(dataLength);
        if (buf) {
            memcpy(buf, data.get(), dataLength);
        } else {
            ALOGE("Failed to writeInplace OperationResult data.");
        }
    }
    outParams.writeToParcel(out);
}

ExportResult::ExportResult() : resultCode(0), exportData(NULL), dataLength(0) {
}

ExportResult::~ExportResult() {
}

void ExportResult::readFromParcel(const Parcel& in) {
    resultCode = in.readInt32();
    ssize_t length = in.readInt32();
    dataLength = 0;
    if (length > 0) {
        const void* buf = in.readInplace(length);
        if (buf) {
            exportData.reset(reinterpret_cast<uint8_t*>(malloc(length)));
            if (exportData.get()) {
                memcpy(exportData.get(), buf, length);
                dataLength = (size_t) length;
            } else {
                ALOGE("Failed to allocate ExportData buffer");
            }
        } else {
            ALOGE("Failed to readInplace ExportData data");
        }
    }
}

void ExportResult::writeToParcel(Parcel* out) const {
    out->writeInt32(resultCode);
    out->writeInt32(dataLength);
    if (exportData && dataLength) {
        void* buf = out->writeInplace(dataLength);
        if (buf) {
            memcpy(buf, exportData.get(), dataLength);
        } else {
            ALOGE("Failed to writeInplace ExportResult data.");
        }
    }
}

KeymasterArguments::KeymasterArguments() {
}

KeymasterArguments::~KeymasterArguments() {
    keymaster_free_param_values(params.data(), params.size());
}

void KeymasterArguments::readFromParcel(const Parcel& in) {
    ssize_t length = in.readInt32();
    size_t ulength = (size_t) length;
    if (length < 0) {
        ulength = 0;
    }
    keymaster_free_param_values(params.data(), params.size());
    params.clear();
    for(size_t i = 0; i < ulength; i++) {
        keymaster_key_param_t param;
        if (!readKeymasterArgumentFromParcel(in, &param)) {
            ALOGE("Error reading keymaster argument from parcel");
            break;
        }
        params.push_back(param);
    }
}

void KeymasterArguments::writeToParcel(Parcel* out) const {
    out->writeInt32(params.size());
    for (auto param : params) {
        out->writeInt32(1);
        writeKeymasterArgumentToParcel(param, out);
    }
}

KeyCharacteristics::KeyCharacteristics() {
    memset((void*) &characteristics, 0, sizeof(characteristics));
}

KeyCharacteristics::~KeyCharacteristics() {
    keymaster_free_characteristics(&characteristics);
}

void KeyCharacteristics::readFromParcel(const Parcel& in) {
    size_t length = 0;
    keymaster_key_param_t* params = readParamList(in, &length);
    characteristics.sw_enforced.params = params;
    characteristics.sw_enforced.length = length;

    params = readParamList(in, &length);
    characteristics.hw_enforced.params = params;
    characteristics.hw_enforced.length = length;
}

void KeyCharacteristics::writeToParcel(Parcel* out) const {
    if (characteristics.sw_enforced.params) {
        out->writeInt32(characteristics.sw_enforced.length);
        for (size_t i = 0; i < characteristics.sw_enforced.length; i++) {
            out->writeInt32(1);
            writeKeymasterArgumentToParcel(characteristics.sw_enforced.params[i], out);
        }
    } else {
        out->writeInt32(0);
    }
    if (characteristics.hw_enforced.params) {
        out->writeInt32(characteristics.hw_enforced.length);
        for (size_t i = 0; i < characteristics.hw_enforced.length; i++) {
            out->writeInt32(1);
            writeKeymasterArgumentToParcel(characteristics.hw_enforced.params[i], out);
        }
    } else {
        out->writeInt32(0);
    }
}

KeymasterCertificateChain::KeymasterCertificateChain() {
    memset(&chain, 0, sizeof(chain));
}

KeymasterCertificateChain::~KeymasterCertificateChain() {
    keymaster_free_cert_chain(&chain);
}

static bool readKeymasterBlob(const Parcel& in, keymaster_blob_t* blob) {
    if (in.readInt32() != 1) {
        return false;
    }

    ssize_t length = in.readInt32();
    if (length <= 0) {
        return false;
    }

    blob->data = reinterpret_cast<const uint8_t*>(malloc(length));
    if (!blob->data)
        return false;

    const void* buf = in.readInplace(length);
    if (!buf)
        return false;

    blob->data_length = static_cast<size_t>(length);
    memcpy(const_cast<uint8_t*>(blob->data), buf, length);

    return true;
}

void KeymasterCertificateChain::readFromParcel(const Parcel& in) {
    keymaster_free_cert_chain(&chain);

    ssize_t count = in.readInt32();
    size_t ucount = count;
    if (count <= 0) {
        return;
    }

    chain.entries = reinterpret_cast<keymaster_blob_t*>(malloc(sizeof(keymaster_blob_t) * ucount));
    if (!chain.entries) {
        ALOGE("Error allocating memory for certificate chain");
        return;
    }

    memset(chain.entries, 0, sizeof(keymaster_blob_t) * ucount);
    for (size_t i = 0; i < ucount; ++i) {
        if (!readKeymasterBlob(in, &chain.entries[i])) {
            ALOGE("Error reading certificate from parcel");
            keymaster_free_cert_chain(&chain);
            return;
        }
    }
}

void KeymasterCertificateChain::writeToParcel(Parcel* out) const {
    out->writeInt32(chain.entry_count);
    for (size_t i = 0; i < chain.entry_count; ++i) {
        if (chain.entries[i].data) {
            out->writeInt32(chain.entries[i].data_length);
            void* buf = out->writeInplace(chain.entries[i].data_length);
            if (buf) {
                memcpy(buf, chain.entries[i].data, chain.entries[i].data_length);
            } else {
                ALOGE("Failed to writeInplace keymaster cert chain entry");
            }
        } else {
            out->writeInt32(0); // Tell Java side this object is NULL.
            ALOGE("Found NULL certificate chain entry");
        }
    }
}

void writeKeymasterArgumentToParcel(const keymaster_key_param_t& param, Parcel* out) {
    switch (keymaster_tag_get_type(param.tag)) {
        case KM_ENUM:
        case KM_ENUM_REP: {
            out->writeInt32(param.tag);
            out->writeInt32(param.enumerated);
            break;
        }
        case KM_UINT:
        case KM_UINT_REP: {
            out->writeInt32(param.tag);
            out->writeInt32(param.integer);
            break;
        }
        case KM_ULONG:
        case KM_ULONG_REP: {
            out->writeInt32(param.tag);
            out->writeInt64(param.long_integer);
            break;
        }
        case KM_DATE: {
            out->writeInt32(param.tag);
            out->writeInt64(param.date_time);
            break;
        }
        case KM_BOOL: {
            out->writeInt32(param.tag);
            break;
        }
        case KM_BIGNUM:
        case KM_BYTES: {
            out->writeInt32(param.tag);
            out->writeInt32(param.blob.data_length);
            void* buf = out->writeInplace(param.blob.data_length);
            if (buf) {
                memcpy(buf, param.blob.data, param.blob.data_length);
            } else {
                ALOGE("Failed to writeInplace keymaster blob param");
            }
            break;
        }
        default: {
            ALOGE("Failed to write argument: Unsupported keymaster_tag_t %d", param.tag);
        }
    }
}


bool readKeymasterArgumentFromParcel(const Parcel& in, keymaster_key_param_t* out) {
    if (in.readInt32() == 0) {
        return false;
    }
    keymaster_tag_t tag = static_cast<keymaster_tag_t>(in.readInt32());
    switch (keymaster_tag_get_type(tag)) {
        case KM_ENUM:
        case KM_ENUM_REP: {
            uint32_t value = in.readInt32();
            *out = keymaster_param_enum(tag, value);
            break;
        }
        case KM_UINT:
        case KM_UINT_REP: {
            uint32_t value = in.readInt32();
            *out = keymaster_param_int(tag, value);
            break;
        }
        case KM_ULONG:
        case KM_ULONG_REP: {
            uint64_t value = in.readInt64();
            *out = keymaster_param_long(tag, value);
            break;
        }
        case KM_DATE: {
            uint64_t value = in.readInt64();
            *out = keymaster_param_date(tag, value);
            break;
        }
        case KM_BOOL: {
            *out = keymaster_param_bool(tag);
            break;
        }
        case KM_BIGNUM:
        case KM_BYTES: {
            ssize_t length = in.readInt32();
            uint8_t* data = NULL;
            size_t ulength = 0;
            if (length >= 0) {
                ulength = (size_t) length;
                // use malloc here so we can use keymaster_free_param_values
                // consistently.
                data = reinterpret_cast<uint8_t*>(malloc(ulength));
                const void* buf = in.readInplace(ulength);
                if (!buf || !data) {
                    ALOGE("Failed to allocate buffer for keymaster blob param");
                    free(data);
                    return false;
                }
                memcpy(data, buf, ulength);
            }
            *out = keymaster_param_blob(tag, data, ulength);
            break;
        }
        default: {
            ALOGE("Unsupported keymaster_tag_t %d", tag);
            return false;
        }
    }
    return true;
}

/**
 * Read a byte array from in. The data at *data is still owned by the parcel
 */
static void readByteArray(const Parcel& in, const uint8_t** data, size_t* length) {
    ssize_t slength = in.readInt32();
    if (slength > 0) {
        *data = reinterpret_cast<const uint8_t*>(in.readInplace(slength));
        if (*data) {
            *length = static_cast<size_t>(slength);
        } else {
            *length = 0;
        }
    } else {
        *data = NULL;
        *length = 0;
    }
}

// Read a keymaster_key_param_t* from a Parcel for use in a
// keymaster_key_characteristics_t. This will be free'd by calling
// keymaster_free_key_characteristics.
static keymaster_key_param_t* readParamList(const Parcel& in, size_t* length) {
    ssize_t slength = in.readInt32();
    *length = 0;
    if (slength < 0) {
        return NULL;
    }
    *length = (size_t) slength;
    if (*length >= UINT_MAX / sizeof(keymaster_key_param_t)) {
        return NULL;
    }
    keymaster_key_param_t* list =
            reinterpret_cast<keymaster_key_param_t*>(malloc(*length *
                                                            sizeof(keymaster_key_param_t)));
    if (!list) {
        ALOGD("Failed to allocate buffer for generateKey outCharacteristics");
        goto err;
    }
    for (size_t i = 0; i < *length ; i++) {
        if (!readKeymasterArgumentFromParcel(in, &list[i])) {
            ALOGE("Failed to read keymaster argument");
            keymaster_free_param_values(list, i);
            goto err;
        }
    }
    return list;
err:
    free(list);
    return NULL;
}

static std::unique_ptr<keymaster_blob_t> readKeymasterBlob(const Parcel& in) {
    std::unique_ptr<keymaster_blob_t> blob (new keymaster_blob_t);
    if (!readKeymasterBlob(in, blob.get())) {
        blob.reset();
    }
    return blob;
}

class BpKeystoreService: public BpInterface<IKeystoreService>
{
public:
    BpKeystoreService(const sp<IBinder>& impl)
        : BpInterface<IKeystoreService>(impl)
    {
    }

    // test ping
    virtual int32_t getState(int32_t userId)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeInt32(userId);
        status_t status = remote()->transact(BnKeystoreService::GET_STATE, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("getState() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("getState() caught exception %d\n", err);
            return -1;
        }
        return ret;
    }

    virtual int32_t get(const String16& name, int32_t uid, uint8_t** item, size_t* itemLength)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(uid);
        status_t status = remote()->transact(BnKeystoreService::GET, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("get() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        ssize_t len = reply.readInt32();
        if (len >= 0 && (size_t) len <= reply.dataAvail()) {
            size_t ulen = (size_t) len;
            const void* buf = reply.readInplace(ulen);
            *item = (uint8_t*) malloc(ulen);
            if (*item != NULL) {
                memcpy(*item, buf, ulen);
                *itemLength = ulen;
            } else {
                ALOGE("out of memory allocating output array in get");
                *itemLength = 0;
            }
        } else {
            *itemLength = 0;
        }
        if (err < 0) {
            ALOGD("get() caught exception %d\n", err);
            return -1;
        }
        return 0;
    }

    virtual int32_t insert(const String16& name, const uint8_t* item, size_t itemLength, int uid,
            int32_t flags)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(itemLength);
        void* buf = data.writeInplace(itemLength);
        memcpy(buf, item, itemLength);
        data.writeInt32(uid);
        data.writeInt32(flags);
        status_t status = remote()->transact(BnKeystoreService::INSERT, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("import() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("import() caught exception %d\n", err);
            return -1;
        }
        return ret;
    }

    virtual int32_t del(const String16& name, int uid)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(uid);
        status_t status = remote()->transact(BnKeystoreService::DEL, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("del() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("del() caught exception %d\n", err);
            return -1;
        }
        return ret;
    }

    virtual int32_t exist(const String16& name, int uid)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(uid);
        status_t status = remote()->transact(BnKeystoreService::EXIST, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("exist() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("exist() caught exception %d\n", err);
            return -1;
        }
        return ret;
    }

    virtual int32_t list(const String16& prefix, int uid, Vector<String16>* matches)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(prefix);
        data.writeInt32(uid);
        status_t status = remote()->transact(BnKeystoreService::LIST, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("list() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t numMatches = reply.readInt32();
        for (int32_t i = 0; i < numMatches; i++) {
            matches->push(reply.readString16());
        }
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("list() caught exception %d\n", err);
            return -1;
        }
        return ret;
    }

    virtual int32_t reset()
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        status_t status = remote()->transact(BnKeystoreService::RESET, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("reset() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("reset() caught exception %d\n", err);
            return -1;
        }
        return ret;
    }

    virtual int32_t onUserPasswordChanged(int32_t userId, const String16& password)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeInt32(userId);
        data.writeString16(password);
        status_t status = remote()->transact(BnKeystoreService::ON_USER_PASSWORD_CHANGED, data,
                                             &reply);
        if (status != NO_ERROR) {
            ALOGD("onUserPasswordChanged() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("onUserPasswordChanged() caught exception %d\n", err);
            return -1;
        }
        return ret;
    }

    virtual int32_t lock(int32_t userId)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeInt32(userId);
        status_t status = remote()->transact(BnKeystoreService::LOCK, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("lock() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("lock() caught exception %d\n", err);
            return -1;
        }
        return ret;
    }

    virtual int32_t unlock(int32_t userId, const String16& password)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeInt32(userId);
        data.writeString16(password);
        status_t status = remote()->transact(BnKeystoreService::UNLOCK, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("unlock() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("unlock() caught exception %d\n", err);
            return -1;
        }
        return ret;
    }

    virtual bool isEmpty(int32_t userId)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeInt32(userId);
        status_t status = remote()->transact(BnKeystoreService::IS_EMPTY, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("isEmpty() could not contact remote: %d\n", status);
            return false;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("isEmpty() caught exception %d\n", err);
            return false;
        }
        return ret != 0;
    }

    virtual int32_t generate(const String16& name, int32_t uid, int32_t keyType, int32_t keySize,
            int32_t flags, Vector<sp<KeystoreArg> >* args)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(uid);
        data.writeInt32(keyType);
        data.writeInt32(keySize);
        data.writeInt32(flags);
        data.writeInt32(1);
        data.writeInt32(args->size());
        for (Vector<sp<KeystoreArg> >::iterator it = args->begin(); it != args->end(); ++it) {
            sp<KeystoreArg> item = *it;
            size_t keyLength = item->size();
            data.writeInt32(keyLength);
            void* buf = data.writeInplace(keyLength);
            memcpy(buf, item->data(), keyLength);
        }
        status_t status = remote()->transact(BnKeystoreService::GENERATE, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("generate() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("generate() caught exception %d\n", err);
            return -1;
        }
        return ret;
    }

    virtual int32_t import(const String16& name, const uint8_t* key, size_t keyLength, int uid,
            int flags)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(keyLength);
        void* buf = data.writeInplace(keyLength);
        memcpy(buf, key, keyLength);
        data.writeInt32(uid);
        data.writeInt32(flags);
        status_t status = remote()->transact(BnKeystoreService::IMPORT, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("import() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("import() caught exception %d\n", err);
            return -1;
        }
        return ret;
    }

    virtual int32_t sign(const String16& name, const uint8_t* in, size_t inLength, uint8_t** out,
            size_t* outLength)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(inLength);
        void* buf = data.writeInplace(inLength);
        memcpy(buf, in, inLength);
        status_t status = remote()->transact(BnKeystoreService::SIGN, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("import() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        ssize_t len = reply.readInt32();
        if (len >= 0 && (size_t) len <= reply.dataAvail()) {
            size_t ulen = (size_t) len;
            const void* outBuf = reply.readInplace(ulen);
            *out = (uint8_t*) malloc(ulen);
            if (*out != NULL) {
                memcpy((void*) *out, outBuf, ulen);
                *outLength = ulen;
            } else {
                ALOGE("out of memory allocating output array in sign");
                *outLength = 0;
            }
        } else {
            *outLength = 0;
        }
        if (err < 0) {
            ALOGD("import() caught exception %d\n", err);
            return -1;
        }
        return 0;
    }

    virtual int32_t verify(const String16& name, const uint8_t* in, size_t inLength,
            const uint8_t* signature, size_t signatureLength)
    {
        Parcel data, reply;
        void* buf;

        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(inLength);
        buf = data.writeInplace(inLength);
        memcpy(buf, in, inLength);
        data.writeInt32(signatureLength);
        buf = data.writeInplace(signatureLength);
        memcpy(buf, signature, signatureLength);
        status_t status = remote()->transact(BnKeystoreService::VERIFY, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("verify() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("verify() caught exception %d\n", err);
            return -1;
        }
        return ret;
    }

    virtual int32_t get_pubkey(const String16& name, uint8_t** pubkey, size_t* pubkeyLength)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        status_t status = remote()->transact(BnKeystoreService::GET_PUBKEY, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("get_pubkey() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        ssize_t len = reply.readInt32();
        if (len >= 0 && (size_t) len <= reply.dataAvail()) {
            size_t ulen = (size_t) len;
            const void* buf = reply.readInplace(ulen);
            *pubkey = (uint8_t*) malloc(ulen);
            if (*pubkey != NULL) {
                memcpy(*pubkey, buf, ulen);
                *pubkeyLength = ulen;
            } else {
                ALOGE("out of memory allocating output array in get_pubkey");
                *pubkeyLength = 0;
            }
        } else {
            *pubkeyLength = 0;
        }
        if (err < 0) {
            ALOGD("get_pubkey() caught exception %d\n", err);
            return -1;
        }
        return 0;
     }

    virtual int32_t grant(const String16& name, int32_t granteeUid)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(granteeUid);
        status_t status = remote()->transact(BnKeystoreService::GRANT, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("grant() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("grant() caught exception %d\n", err);
            return -1;
        }
        return ret;
    }

    virtual int32_t ungrant(const String16& name, int32_t granteeUid)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(granteeUid);
        status_t status = remote()->transact(BnKeystoreService::UNGRANT, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("ungrant() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("ungrant() caught exception %d\n", err);
            return -1;
        }
        return ret;
    }

    int64_t getmtime(const String16& name, int32_t uid)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(uid);
        status_t status = remote()->transact(BnKeystoreService::GETMTIME, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("getmtime() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int64_t ret = reply.readInt64();
        if (err < 0) {
            ALOGD("getmtime() caught exception %d\n", err);
            return -1;
        }
        return ret;
    }

    virtual int32_t duplicate(const String16& srcKey, int32_t srcUid, const String16& destKey,
            int32_t destUid)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(srcKey);
        data.writeInt32(srcUid);
        data.writeString16(destKey);
        data.writeInt32(destUid);
        status_t status = remote()->transact(BnKeystoreService::DUPLICATE, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("duplicate() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("duplicate() caught exception %d\n", err);
            return -1;
        }
        return ret;
    }

    virtual int32_t is_hardware_backed(const String16& keyType)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(keyType);
        status_t status = remote()->transact(BnKeystoreService::IS_HARDWARE_BACKED, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("is_hardware_backed() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("is_hardware_backed() caught exception %d\n", err);
            return -1;
        }
        return ret;
    }

    virtual int32_t clear_uid(int64_t uid)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeInt64(uid);
        status_t status = remote()->transact(BnKeystoreService::CLEAR_UID, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("clear_uid() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("clear_uid() caught exception %d\n", err);
            return -1;
        }
        return ret;
    }

    virtual int32_t addRngEntropy(const uint8_t* buf, size_t bufLength)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeByteArray(bufLength, buf);
        status_t status = remote()->transact(BnKeystoreService::ADD_RNG_ENTROPY, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("addRngEntropy() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("addRngEntropy() caught exception %d\n", err);
            return -1;
        }
        return ret;
    };

    virtual int32_t generateKey(const String16& name, const KeymasterArguments& params,
                                const uint8_t* entropy, size_t entropyLength, int uid, int flags,
                                KeyCharacteristics* outCharacteristics)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(1);
        params.writeToParcel(&data);
        data.writeByteArray(entropyLength, entropy);
        data.writeInt32(uid);
        data.writeInt32(flags);
        status_t status = remote()->transact(BnKeystoreService::GENERATE_KEY, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("generateKey() could not contact remote: %d\n", status);
            return KM_ERROR_UNKNOWN_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("generateKey() caught exception %d\n", err);
            return KM_ERROR_UNKNOWN_ERROR;
        }
        if (reply.readInt32() != 0 && outCharacteristics) {
            outCharacteristics->readFromParcel(reply);
        }
        return ret;
    }
    virtual int32_t getKeyCharacteristics(const String16& name,
                                          const keymaster_blob_t* clientId,
                                          const keymaster_blob_t* appData,
                                          int32_t uid, KeyCharacteristics* outCharacteristics)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        if (clientId) {
            data.writeByteArray(clientId->data_length, clientId->data);
        } else {
            data.writeInt32(-1);
        }
        if (appData) {
            data.writeByteArray(appData->data_length, appData->data);
        } else {
            data.writeInt32(-1);
        }
        data.writeInt32(uid);
        status_t status = remote()->transact(BnKeystoreService::GET_KEY_CHARACTERISTICS,
                                             data, &reply);
        if (status != NO_ERROR) {
            ALOGD("getKeyCharacteristics() could not contact remote: %d\n", status);
            return KM_ERROR_UNKNOWN_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("getKeyCharacteristics() caught exception %d\n", err);
            return KM_ERROR_UNKNOWN_ERROR;
        }
        if (reply.readInt32() != 0 && outCharacteristics) {
            outCharacteristics->readFromParcel(reply);
        }
        return ret;
    }
    virtual int32_t importKey(const String16& name, const KeymasterArguments&  params,
                              keymaster_key_format_t format, const uint8_t *keyData,
                              size_t keyLength, int uid, int flags,
                              KeyCharacteristics* outCharacteristics)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(1);
        params.writeToParcel(&data);
        data.writeInt32(format);
        data.writeByteArray(keyLength, keyData);
        data.writeInt32(uid);
        data.writeInt32(flags);
        status_t status = remote()->transact(BnKeystoreService::IMPORT_KEY, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("importKey() could not contact remote: %d\n", status);
            return KM_ERROR_UNKNOWN_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("importKey() caught exception %d\n", err);
            return KM_ERROR_UNKNOWN_ERROR;
        }
        if (reply.readInt32() != 0 && outCharacteristics) {
            outCharacteristics->readFromParcel(reply);
        }
        return ret;
    }

    virtual void exportKey(const String16& name, keymaster_key_format_t format,
                           const keymaster_blob_t* clientId,
                           const keymaster_blob_t* appData, int32_t uid, ExportResult* result)
    {
        if (!result) {
            return;
        }

        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(format);
        if (clientId) {
            data.writeByteArray(clientId->data_length, clientId->data);
        } else {
            data.writeInt32(-1);
        }
        if (appData) {
            data.writeByteArray(appData->data_length, appData->data);
        } else {
            data.writeInt32(-1);
        }
        data.writeInt32(uid);
        status_t status = remote()->transact(BnKeystoreService::EXPORT_KEY, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("exportKey() could not contact remote: %d\n", status);
            result->resultCode = KM_ERROR_UNKNOWN_ERROR;
            return;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("exportKey() caught exception %d\n", err);
            result->resultCode = KM_ERROR_UNKNOWN_ERROR;
            return;
        }
        if (reply.readInt32() != 0) {
            result->readFromParcel(reply);
        }
    }

    virtual void begin(const sp<IBinder>& appToken, const String16& name,
                       keymaster_purpose_t purpose, bool pruneable,
                       const KeymasterArguments& params, const uint8_t* entropy,
                       size_t entropyLength, int32_t uid, OperationResult* result)
    {
        if (!result) {
            return;
        }
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeStrongBinder(appToken);
        data.writeString16(name);
        data.writeInt32(purpose);
        data.writeInt32(pruneable ? 1 : 0);
        data.writeInt32(1);
        params.writeToParcel(&data);
        data.writeByteArray(entropyLength, entropy);
        data.writeInt32(uid);
        status_t status = remote()->transact(BnKeystoreService::BEGIN, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("begin() could not contact remote: %d\n", status);
            result->resultCode = KM_ERROR_UNKNOWN_ERROR;
            return;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("begin() caught exception %d\n", err);
            result->resultCode = KM_ERROR_UNKNOWN_ERROR;
            return;
        }
        if (reply.readInt32() != 0) {
            result->readFromParcel(reply);
        }
    }

    virtual void update(const sp<IBinder>& token, const KeymasterArguments& params,
                        const uint8_t* opData, size_t dataLength, OperationResult* result)
    {
        if (!result) {
            return;
        }
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeStrongBinder(token);
        data.writeInt32(1);
        params.writeToParcel(&data);
        data.writeByteArray(dataLength, opData);
        status_t status = remote()->transact(BnKeystoreService::UPDATE, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("update() could not contact remote: %d\n", status);
            result->resultCode = KM_ERROR_UNKNOWN_ERROR;
            return;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("update() caught exception %d\n", err);
            result->resultCode = KM_ERROR_UNKNOWN_ERROR;
            return;
        }
        if (reply.readInt32() != 0) {
            result->readFromParcel(reply);
        }
    }

    virtual void finish(const sp<IBinder>& token, const KeymasterArguments& params,
                        const uint8_t* signature, size_t signatureLength,
                        const uint8_t* entropy, size_t entropyLength,
                        OperationResult* result)
    {
        if (!result) {
            return;
        }
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeStrongBinder(token);
        data.writeInt32(1);
        params.writeToParcel(&data);
        data.writeByteArray(signatureLength, signature);
        data.writeByteArray(entropyLength, entropy);
        status_t status = remote()->transact(BnKeystoreService::FINISH, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("finish() could not contact remote: %d\n", status);
            result->resultCode = KM_ERROR_UNKNOWN_ERROR;
            return;
        }
        int32_t err = reply.readExceptionCode();
        if (err < 0) {
            ALOGD("finish() caught exception %d\n", err);
            result->resultCode = KM_ERROR_UNKNOWN_ERROR;
            return;
        }
        if (reply.readInt32() != 0) {
            result->readFromParcel(reply);
        }
    }

    virtual int32_t abort(const sp<IBinder>& token)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeStrongBinder(token);
        status_t status = remote()->transact(BnKeystoreService::ABORT, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("abort() could not contact remote: %d\n", status);
            return KM_ERROR_UNKNOWN_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("abort() caught exception %d\n", err);
            return KM_ERROR_UNKNOWN_ERROR;
        }
        return ret;
    }

    virtual bool isOperationAuthorized(const sp<IBinder>& token)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeStrongBinder(token);
        status_t status = remote()->transact(BnKeystoreService::IS_OPERATION_AUTHORIZED, data,
                                             &reply);
        if (status != NO_ERROR) {
            ALOGD("isOperationAuthorized() could not contact remote: %d\n", status);
            return false;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("isOperationAuthorized() caught exception %d\n", err);
            return false;
        }
        return ret == 1;
    }

    virtual int32_t addAuthToken(const uint8_t* token, size_t length)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeByteArray(length, token);
        status_t status = remote()->transact(BnKeystoreService::ADD_AUTH_TOKEN, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("addAuthToken() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("addAuthToken() caught exception %d\n", err);
            return -1;
        }
        return ret;
    };

    virtual int32_t onUserAdded(int32_t userId, int32_t parentId)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeInt32(userId);
        data.writeInt32(parentId);
        status_t status = remote()->transact(BnKeystoreService::ON_USER_ADDED, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("onUserAdded() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("onUserAdded() caught exception %d\n", err);
            return -1;
        }
        return ret;
    }

    virtual int32_t onUserRemoved(int32_t userId)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeInt32(userId);
        status_t status = remote()->transact(BnKeystoreService::ON_USER_REMOVED, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("onUserRemoved() could not contact remote: %d\n", status);
            return -1;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("onUserRemoved() caught exception %d\n", err);
            return -1;
        }
        return ret;
    }

    virtual int32_t attestKey(const String16& name, const KeymasterArguments& params,
                              KeymasterCertificateChain* outChain) {
        if (!outChain)
            return KM_ERROR_OUTPUT_PARAMETER_NULL;

        Parcel data, reply;
        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeInt32(1);  // params is not NULL.
        params.writeToParcel(&data);

        status_t status = remote()->transact(BnKeystoreService::ATTEST_KEY, data, &reply);
        if (status != NO_ERROR) {
            ALOGD("attestkey() count not contact remote: %d\n", status);
            return KM_ERROR_UNKNOWN_ERROR;
        }
        int32_t err = reply.readExceptionCode();
        int32_t ret = reply.readInt32();
        if (err < 0) {
            ALOGD("attestKey() caught exception %d\n", err);
            return KM_ERROR_UNKNOWN_ERROR;
        }
        if (reply.readInt32() != 0) {
            outChain->readFromParcel(reply);
        }
        return ret;
    }

};

IMPLEMENT_META_INTERFACE(KeystoreService, "android.security.IKeystoreService");

// ----------------------------------------------------------------------

status_t BnKeystoreService::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch(code) {
        case GET_STATE: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            int32_t userId = data.readInt32();
            int32_t ret = getState(userId);
            reply->writeNoException();
            reply->writeInt32(ret);
            return NO_ERROR;
        } break;
        case GET: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            String16 name = data.readString16();
            int32_t uid = data.readInt32();
            void* out = NULL;
            size_t outSize = 0;
            int32_t ret = get(name, uid, (uint8_t**) &out, &outSize);
            reply->writeNoException();
            if (ret == 1) {
                reply->writeInt32(outSize);
                void* buf = reply->writeInplace(outSize);
                memcpy(buf, out, outSize);
                free(out);
            } else {
                reply->writeInt32(-1);
            }
            return NO_ERROR;
        } break;
        case INSERT: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            String16 name = data.readString16();
            ssize_t inSize = data.readInt32();
            const void* in;
            if (inSize >= 0 && (size_t) inSize <= data.dataAvail()) {
                in = data.readInplace(inSize);
            } else {
                in = NULL;
                inSize = 0;
            }
            int uid = data.readInt32();
            int32_t flags = data.readInt32();
            int32_t ret = insert(name, (const uint8_t*) in, (size_t) inSize, uid, flags);
            reply->writeNoException();
            reply->writeInt32(ret);
            return NO_ERROR;
        } break;
        case DEL: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            String16 name = data.readString16();
            int uid = data.readInt32();
            int32_t ret = del(name, uid);
            reply->writeNoException();
            reply->writeInt32(ret);
            return NO_ERROR;
        } break;
        case EXIST: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            String16 name = data.readString16();
            int uid = data.readInt32();
            int32_t ret = exist(name, uid);
            reply->writeNoException();
            reply->writeInt32(ret);
            return NO_ERROR;
        } break;
        case LIST: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            String16 prefix = data.readString16();
            int uid = data.readInt32();
            Vector<String16> matches;
            int32_t ret = list(prefix, uid, &matches);
            reply->writeNoException();
            reply->writeInt32(matches.size());
            Vector<String16>::const_iterator it = matches.begin();
            for (; it != matches.end(); ++it) {
                reply->writeString16(*it);
            }
            reply->writeInt32(ret);
            return NO_ERROR;
        } break;
        case RESET: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            int32_t ret = reset();
            reply->writeNoException();
            reply->writeInt32(ret);
            return NO_ERROR;
        } break;
        case ON_USER_PASSWORD_CHANGED: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            int32_t userId = data.readInt32();
            String16 pass = data.readString16();
            int32_t ret = onUserPasswordChanged(userId, pass);
            reply->writeNoException();
            reply->writeInt32(ret);
            return NO_ERROR;
        } break;
        case LOCK: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            int32_t userId = data.readInt32();
            int32_t ret = lock(userId);
            reply->writeNoException();
            reply->writeInt32(ret);
            return NO_ERROR;
        } break;
        case UNLOCK: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            int32_t userId = data.readInt32();
            String16 pass = data.readString16();
            int32_t ret = unlock(userId, pass);
            reply->writeNoException();
            reply->writeInt32(ret);
            return NO_ERROR;
        } break;
        case IS_EMPTY: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            int32_t userId = data.readInt32();
            bool ret = isEmpty(userId);
            reply->writeNoException();
            reply->writeInt32(ret ? 1 : 0);
            return NO_ERROR;
        } break;
        case GENERATE: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            String16 name = data.readString16();
            int32_t uid = data.readInt32();
            int32_t keyType = data.readInt32();
            int32_t keySize = data.readInt32();
            int32_t flags = data.readInt32();
            Vector<sp<KeystoreArg> > args;
            int32_t argsPresent = data.readInt32();
            if (argsPresent == 1) {
                ssize_t numArgs = data.readInt32();
                if (numArgs > MAX_GENERATE_ARGS) {
                    return BAD_VALUE;
                }
                if (numArgs > 0) {
                    for (size_t i = 0; i < (size_t) numArgs; i++) {
                        ssize_t inSize = data.readInt32();
                        if (inSize >= 0 && (size_t) inSize <= data.dataAvail()) {
                            sp<KeystoreArg> arg = new KeystoreArg(data.readInplace(inSize),
                                                                  inSize);
                            args.push_back(arg);
                        } else {
                            args.push_back(NULL);
                        }
                    }
                }
            }
            int32_t ret = generate(name, uid, keyType, keySize, flags, &args);
            reply->writeNoException();
            reply->writeInt32(ret);
            return NO_ERROR;
        } break;
        case IMPORT: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            String16 name = data.readString16();
            ssize_t inSize = data.readInt32();
            const void* in;
            if (inSize >= 0 && (size_t) inSize <= data.dataAvail()) {
                in = data.readInplace(inSize);
            } else {
                in = NULL;
                inSize = 0;
            }
            int uid = data.readInt32();
            int32_t flags = data.readInt32();
            int32_t ret = import(name, (const uint8_t*) in, (size_t) inSize, uid, flags);
            reply->writeNoException();
            reply->writeInt32(ret);
            return NO_ERROR;
        } break;
        case SIGN: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            String16 name = data.readString16();
            ssize_t inSize = data.readInt32();
            const void* in;
            if (inSize >= 0 && (size_t) inSize <= data.dataAvail()) {
                in = data.readInplace(inSize);
            } else {
                in = NULL;
                inSize = 0;
            }
            void* out = NULL;
            size_t outSize = 0;
            int32_t ret = sign(name, (const uint8_t*) in, (size_t) inSize, (uint8_t**) &out, &outSize);
            reply->writeNoException();
            if (outSize > 0 && out != NULL) {
                reply->writeInt32(outSize);
                void* buf = reply->writeInplace(outSize);
                memcpy(buf, out, outSize);
                delete[] reinterpret_cast<uint8_t*>(out);
            } else {
                reply->writeInt32(-1);
            }
            reply->writeInt32(ret);
            return NO_ERROR;
        } break;
        case VERIFY: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            String16 name = data.readString16();
            ssize_t inSize = data.readInt32();
            const void* in;
            if (inSize >= 0 && (size_t) inSize <= data.dataAvail()) {
                in = data.readInplace(inSize);
            } else {
                in = NULL;
                inSize = 0;
            }
            ssize_t sigSize = data.readInt32();
            const void* sig;
            if (sigSize >= 0 && (size_t) sigSize <= data.dataAvail()) {
                sig = data.readInplace(sigSize);
            } else {
                sig = NULL;
                sigSize = 0;
            }
            bool ret = verify(name, (const uint8_t*) in, (size_t) inSize, (const uint8_t*) sig,
                    (size_t) sigSize);
            reply->writeNoException();
            reply->writeInt32(ret ? 1 : 0);
            return NO_ERROR;
        } break;
        case GET_PUBKEY: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            String16 name = data.readString16();
            void* out = NULL;
            size_t outSize = 0;
            int32_t ret = get_pubkey(name, (unsigned char**) &out, &outSize);
            reply->writeNoException();
            if (outSize > 0 && out != NULL) {
                reply->writeInt32(outSize);
                void* buf = reply->writeInplace(outSize);
                memcpy(buf, out, outSize);
                free(out);
            } else {
                reply->writeInt32(-1);
            }
            reply->writeInt32(ret);
            return NO_ERROR;
        } break;
        case GRANT: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            String16 name = data.readString16();
            int32_t granteeUid = data.readInt32();
            int32_t ret = grant(name, granteeUid);
            reply->writeNoException();
            reply->writeInt32(ret);
            return NO_ERROR;
        } break;
        case UNGRANT: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            String16 name = data.readString16();
            int32_t granteeUid = data.readInt32();
            int32_t ret = ungrant(name, granteeUid);
            reply->writeNoException();
            reply->writeInt32(ret);
            return NO_ERROR;
        } break;
        case GETMTIME: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            String16 name = data.readString16();
            int32_t uid = data.readInt32();
            int64_t ret = getmtime(name, uid);
            reply->writeNoException();
            reply->writeInt64(ret);
            return NO_ERROR;
        } break;
        case DUPLICATE: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            String16 srcKey = data.readString16();
            int32_t srcUid = data.readInt32();
            String16 destKey = data.readString16();
            int32_t destUid = data.readInt32();
            int32_t ret = duplicate(srcKey, srcUid, destKey, destUid);
            reply->writeNoException();
            reply->writeInt32(ret);
            return NO_ERROR;
        } break;
        case IS_HARDWARE_BACKED: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            String16 keyType = data.readString16();
            int32_t ret = is_hardware_backed(keyType);
            reply->writeNoException();
            reply->writeInt32(ret);
            return NO_ERROR;
        }
        case CLEAR_UID: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            int64_t uid = data.readInt64();
            int32_t ret = clear_uid(uid);
            reply->writeNoException();
            reply->writeInt32(ret);
            return NO_ERROR;
        }
        case ADD_RNG_ENTROPY: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            const uint8_t* bytes = NULL;
            size_t size = 0;
            readByteArray(data, &bytes, &size);
            int32_t ret = addRngEntropy(bytes, size);
            reply->writeNoException();
            reply->writeInt32(ret);
            return NO_ERROR;
        }
        case GENERATE_KEY: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            String16 name = data.readString16();
            KeymasterArguments args;
            if (data.readInt32() != 0) {
                args.readFromParcel(data);
            }
            const uint8_t* entropy = NULL;
            size_t entropyLength = 0;
            readByteArray(data, &entropy, &entropyLength);
            int32_t uid = data.readInt32();
            int32_t flags = data.readInt32();
            KeyCharacteristics outCharacteristics;
            int32_t ret = generateKey(name, args, entropy, entropyLength, uid, flags,
                                      &outCharacteristics);
            reply->writeNoException();
            reply->writeInt32(ret);
            reply->writeInt32(1);
            outCharacteristics.writeToParcel(reply);
            return NO_ERROR;
        }
        case GET_KEY_CHARACTERISTICS: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            String16 name = data.readString16();
            std::unique_ptr<keymaster_blob_t> clientId = readKeymasterBlob(data);
            std::unique_ptr<keymaster_blob_t> appData = readKeymasterBlob(data);
            int32_t uid = data.readInt32();
            KeyCharacteristics outCharacteristics;
            int ret = getKeyCharacteristics(name, clientId.get(), appData.get(), uid,
                                            &outCharacteristics);
            reply->writeNoException();
            reply->writeInt32(ret);
            reply->writeInt32(1);
            outCharacteristics.writeToParcel(reply);
            return NO_ERROR;
        }
        case IMPORT_KEY: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            String16 name = data.readString16();
            KeymasterArguments args;
            if (data.readInt32() != 0) {
                args.readFromParcel(data);
            }
            keymaster_key_format_t format = static_cast<keymaster_key_format_t>(data.readInt32());
            const uint8_t* keyData = NULL;
            size_t keyLength = 0;
            readByteArray(data, &keyData, &keyLength);
            int32_t uid = data.readInt32();
            int32_t flags = data.readInt32();
            KeyCharacteristics outCharacteristics;
            int32_t ret = importKey(name, args, format, keyData, keyLength, uid, flags,
                                    &outCharacteristics);
            reply->writeNoException();
            reply->writeInt32(ret);
            reply->writeInt32(1);
            outCharacteristics.writeToParcel(reply);

            return NO_ERROR;
        }
        case EXPORT_KEY: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            String16 name = data.readString16();
            keymaster_key_format_t format = static_cast<keymaster_key_format_t>(data.readInt32());
            std::unique_ptr<keymaster_blob_t> clientId = readKeymasterBlob(data);
            std::unique_ptr<keymaster_blob_t> appData = readKeymasterBlob(data);
            int32_t uid = data.readInt32();
            ExportResult result;
            exportKey(name, format, clientId.get(), appData.get(), uid, &result);
            reply->writeNoException();
            reply->writeInt32(1);
            result.writeToParcel(reply);

            return NO_ERROR;
        }
        case BEGIN: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            sp<IBinder> token = data.readStrongBinder();
            String16 name = data.readString16();
            keymaster_purpose_t purpose = static_cast<keymaster_purpose_t>(data.readInt32());
            bool pruneable = data.readInt32() != 0;
            KeymasterArguments args;
            if (data.readInt32() != 0) {
                args.readFromParcel(data);
            }
            const uint8_t* entropy = NULL;
            size_t entropyLength = 0;
            readByteArray(data, &entropy, &entropyLength);
            int32_t uid = data.readInt32();
            OperationResult result;
            begin(token, name, purpose, pruneable, args, entropy, entropyLength, uid, &result);
            reply->writeNoException();
            reply->writeInt32(1);
            result.writeToParcel(reply);

            return NO_ERROR;
        }
        case UPDATE: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            sp<IBinder> token = data.readStrongBinder();
            KeymasterArguments args;
            if (data.readInt32() != 0) {
                args.readFromParcel(data);
            }
            const uint8_t* buf = NULL;
            size_t bufLength = 0;
            readByteArray(data, &buf, &bufLength);
            OperationResult result;
            update(token, args, buf, bufLength, &result);
            reply->writeNoException();
            reply->writeInt32(1);
            result.writeToParcel(reply);

            return NO_ERROR;
        }
        case FINISH: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            sp<IBinder> token = data.readStrongBinder();
            KeymasterArguments args;
            if (data.readInt32() != 0) {
                args.readFromParcel(data);
            }
            const uint8_t* signature = NULL;
            size_t signatureLength = 0;
            readByteArray(data, &signature, &signatureLength);
            const uint8_t* entropy = NULL;
            size_t entropyLength = 0;
            readByteArray(data, &entropy, &entropyLength);
            OperationResult result;
            finish(token, args, signature, signatureLength, entropy, entropyLength,  &result);
            reply->writeNoException();
            reply->writeInt32(1);
            result.writeToParcel(reply);

            return NO_ERROR;
        }
        case ABORT: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            sp<IBinder> token = data.readStrongBinder();
            int32_t result = abort(token);
            reply->writeNoException();
            reply->writeInt32(result);

            return NO_ERROR;
        }
        case IS_OPERATION_AUTHORIZED: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            sp<IBinder> token = data.readStrongBinder();
            bool result = isOperationAuthorized(token);
            reply->writeNoException();
            reply->writeInt32(result ? 1 : 0);

            return NO_ERROR;
        }
        case ADD_AUTH_TOKEN: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            const uint8_t* token_bytes = NULL;
            size_t size = 0;
            readByteArray(data, &token_bytes, &size);
            int32_t result = addAuthToken(token_bytes, size);
            reply->writeNoException();
            reply->writeInt32(result);

            return NO_ERROR;
        }
        case ON_USER_ADDED: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            int32_t userId = data.readInt32();
            int32_t parentId = data.readInt32();
            int32_t result = onUserAdded(userId, parentId);
            reply->writeNoException();
            reply->writeInt32(result);

            return NO_ERROR;
        }
        case ON_USER_REMOVED: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            int32_t userId = data.readInt32();
            int32_t result = onUserRemoved(userId);
            reply->writeNoException();
            reply->writeInt32(result);

            return NO_ERROR;
        }
        case ATTEST_KEY: {
            CHECK_INTERFACE(IKeystoreService, data, reply);
            String16 name = data.readString16();
            KeymasterArguments params;
            if (data.readInt32() != 0) {
                params.readFromParcel(data);
            }
            KeymasterCertificateChain chain;
            int ret = attestKey(name, params, &chain);
            reply->writeNoException();
            reply->writeInt32(ret);
            reply->writeInt32(1);
            chain.writeToParcel(reply);

            return NO_ERROR;
        }
        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
}

// ----------------------------------------------------------------------------

}; // namespace android