/* * 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. */ #include <keystore.h> #include <keystore_client.h> #include <cutils/sockets.h> #define LOG_TAG "keystore_client" #include <cutils/log.h> ResponseCode keystore_cmd(command_code_t cmd, Keystore_Reply* reply, int numArgs, ...) { int sock; sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); if (sock == -1) { return SYSTEM_ERROR; } if (TEMP_FAILURE_RETRY(send(sock, &cmd, 1, MSG_NOSIGNAL)) != 1) { close(sock); return SYSTEM_ERROR; } va_list vl; va_start(vl, numArgs); for (int i = 0; i < numArgs; i++) { size_t argLen = va_arg(vl, size_t); uint8_t* arg = va_arg(vl, uint8_t*); if (argLen > KEYSTORE_MESSAGE_SIZE) { ALOGE("code called us with an argLen out of bounds: %llu", (unsigned long long) argLen); close(sock); return SYSTEM_ERROR; } uint8_t bytes[2] = { argLen >> 8, argLen }; if (TEMP_FAILURE_RETRY(send(sock, bytes, 2, MSG_NOSIGNAL)) != 2 || TEMP_FAILURE_RETRY(send(sock, arg, argLen, MSG_NOSIGNAL)) != static_cast<ssize_t>(argLen)) { ALOGW("truncated write to keystore"); close(sock); return SYSTEM_ERROR; } } va_end(vl); uint8_t code = 0; if (shutdown(sock, SHUT_WR) != 0 || TEMP_FAILURE_RETRY(recv(sock, &code, 1, 0)) != 1 || code != NO_ERROR) { ALOGW("Error from keystore: %d", code); close(sock); return SYSTEM_ERROR; } if (reply != NULL) { reply->setCode(static_cast<ResponseCode>(code)); uint8_t bytes[2]; uint8_t* data = reply->get(); if (TEMP_FAILURE_RETRY(recv(sock, &bytes[0], 1, 0)) == 1 && TEMP_FAILURE_RETRY(recv(sock, &bytes[1], 1, 0)) == 1) { int offset = 0; int length = bytes[0] << 8 | bytes[1]; while (offset < length) { int n = TEMP_FAILURE_RETRY(recv(sock, &data[offset], length - offset, 0)); if (n <= 0) { ALOGW("truncated read from keystore for data"); code = SYSTEM_ERROR; break; } offset += n; } reply->setLength(length); } else { ALOGW("truncated read from keystore for length"); code = SYSTEM_ERROR; } } close(sock); return static_cast<ResponseCode>(code); } Keystore_Reply::Keystore_Reply() : mCode(SYSTEM_ERROR) , mLength(-1) { mData = new uint8_t[KEYSTORE_MESSAGE_SIZE]; } Keystore_Reply::~Keystore_Reply() { delete[] mData; } uint8_t* Keystore_Reply::get() { return mData; } void Keystore_Reply::setLength(size_t length) { mLength = length; } size_t Keystore_Reply::length() const { return mLength; } void Keystore_Reply::setCode(ResponseCode code) { mCode = code; } ResponseCode Keystore_Reply::code() const { return mCode; } uint8_t* Keystore_Reply::release() { uint8_t* data = mData; mData = NULL; return data; }