/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <stdio.h> #include <stdint.h> #include <string.h> #include <sys/types.h> #include <vector> #include <android/security/keystore/IKeystoreService.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <keystore/keystore.h> using namespace android; using namespace keystore; using android::security::keystore::IKeystoreService; static const char* responses[] = { nullptr, /* [NO_ERROR] = */ "No error", /* [LOCKED] = */ "Locked", /* [UNINITIALIZED] = */ "Uninitialized", /* [SYSTEM_ERROR] = */ "System error", /* [PROTOCOL_ERROR] = */ "Protocol error", /* [PERMISSION_DENIED] = */ "Permission denied", /* [KEY_NOT_FOUND] = */ "Key not found", /* [VALUE_CORRUPTED] = */ "Value corrupted", /* [UNDEFINED_ACTION] = */ "Undefined action", /* [WRONG_PASSWORD] = */ "Wrong password (last chance)", /* [WRONG_PASSWORD + 1] = */ "Wrong password (2 tries left)", /* [WRONG_PASSWORD + 2] = */ "Wrong password (3 tries left)", /* [WRONG_PASSWORD + 3] = */ "Wrong password (4 tries left)", }; #define NO_ARG_INT_RETURN(cmd) \ do { \ if (strcmp(argv[1], #cmd) == 0) { \ int32_t ret = -1; \ service->cmd(&ret); \ if (ret < 0) { \ fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \ return 1; \ } else { \ printf(#cmd ": %s (%d)\n", responses[ret], ret); \ return 0; \ } \ } \ } while (0) #define SINGLE_ARG_INT_RETURN(cmd) \ do { \ if (strcmp(argv[1], #cmd) == 0) { \ if (argc < 3) { \ fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \ return 1; \ } \ int32_t ret = -1; \ service->cmd(String16(argv[2]), &ret); \ if (ret < 0) { \ fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \ return 1; \ } else { \ printf(#cmd ": %s (%d)\n", responses[ret], ret); \ return 0; \ } \ } \ } while (0) #define SINGLE_INT_ARG_INT_RETURN(cmd) \ do { \ if (strcmp(argv[1], #cmd) == 0) { \ if (argc < 3) { \ fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \ return 1; \ } \ int32_t ret = -1; \ service->cmd(atoi(argv[2]), &ret); \ if (ret < 0) { \ fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \ return 1; \ } else { \ printf(#cmd ": %s (%d)\n", responses[ret], ret); \ return 0; \ } \ } \ } while (0) #define SINGLE_ARG_PLUS_UID_INT_RETURN(cmd) \ do { \ if (strcmp(argv[1], #cmd) == 0) { \ if (argc < 3) { \ fprintf(stderr, "Usage: %s " #cmd " <name> <uid>\n", argv[0]); \ return 1; \ } \ int uid = -1; \ if (argc > 3) { \ uid = atoi(argv[3]); \ fprintf(stderr, "Running as uid %d\n", uid); \ } \ int32_t ret = -1; \ service->cmd(String16(argv[2]), uid, &ret); \ if (ret < 0) { \ fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \ return 1; \ } else { \ printf(#cmd ": %s (%d)\n", responses[ret], ret); \ return 0; \ } \ } \ } while (0) #define SINGLE_ARG_PLUS_UID_DATA_RETURN(cmd) \ do { \ if (strcmp(argv[1], #cmd) == 0) { \ if (argc < 3) { \ fprintf(stderr, "Usage: %s " #cmd " <name> <uid>\n", argv[0]); \ return 1; \ } \ std::vector<uint8_t> data; \ int uid = -1; \ if (argc > 3) { \ uid = atoi(argv[3]); \ fprintf(stderr, "Running as uid %d\n", uid); \ } \ ::android::binder::Status ret = service->cmd(String16(argv[2]), uid, &data); \ if (!ret.isOk()) { \ fprintf(stderr, "Exception code: %d\n", ret.exceptionCode()); \ return 1; \ } else { \ fwrite(&data[0], data.size(), 1, stdout); \ fflush(stdout); \ return 0; \ } \ } \ } while (0) #define STRING_ARG_DATA_STDIN_INT_RETURN(cmd) \ do { \ if (strcmp(argv[1], #cmd) == 0) { \ if (argc < 3) { \ fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \ return 1; \ } \ uint8_t* data; \ size_t dataSize; \ read_input(&data, &dataSize); \ int32_t ret = -1; \ service->cmd(String16(argv[2]), data, dataSize, &ret); \ if (ret < 0) { \ fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \ return 1; \ } else { \ printf(#cmd ": %s (%d)\n", responses[ret], ret); \ return 0; \ } \ } \ } while (0) #define SINGLE_ARG_DATA_RETURN(cmd) \ do { \ if (strcmp(argv[1], #cmd) == 0) { \ if (argc < 3) { \ fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \ return 1; \ } \ std::vector<uint8_t> data; \ ::android::binder::Status ret = service->cmd(String16(argv[2]), &data); \ if (!ret.isOk()) { \ fprintf(stderr, "Exception code: %d\n", ret.exceptionCode()); \ return 1; \ } else { \ fwrite(&data[0], data.size(), 1, stdout); \ fflush(stdout); \ return 0; \ } \ } \ } while (0) static int list(const sp<IKeystoreService>& service, const String16& name, int uid) { std::vector<String16> matches; ::android::binder::Status ret = service->list(name, uid, &matches); if (!ret.isOk()) { fprintf(stderr, "list: exception (%d)\n", ret.exceptionCode()); return 1; } else { std::vector<String16>::const_iterator it = matches.begin(); for (; it != matches.end(); ++it) { printf("%s\n", String8(*it).string()); } return 0; } } int main(int argc, char* argv[]) { if (argc < 2) { fprintf(stderr, "Usage: %s action [parameter ...]\n", argv[0]); return 1; } sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder = sm->getService(String16("android.security.keystore")); sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder); if (service == nullptr) { fprintf(stderr, "%s: error: could not connect to keystore service\n", argv[0]); return 1; } /* * All the commands should return a value */ SINGLE_INT_ARG_INT_RETURN(getState); SINGLE_ARG_PLUS_UID_DATA_RETURN(get); // TODO: insert SINGLE_ARG_PLUS_UID_INT_RETURN(del); SINGLE_ARG_PLUS_UID_INT_RETURN(exist); if (strcmp(argv[1], "list") == 0) { return list(service, argc < 3 ? String16("") : String16(argv[2]), argc < 4 ? -1 : atoi(argv[3])); } NO_ARG_INT_RETURN(reset); // TODO: notifyUserPasswordChanged SINGLE_INT_ARG_INT_RETURN(lock); // TODO: unlock SINGLE_INT_ARG_INT_RETURN(isEmpty); // TODO: generate // TODO: grant // TODO: ungrant // TODO: getmtime fprintf(stderr, "%s: unknown command: %s\n", argv[0], argv[1]); return 1; }