1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <stdio.h> 18 #include <stdint.h> 19 #include <string.h> 20 #include <sys/types.h> 21 22 #include <keystore/IKeystoreService.h> 23 #include <binder/IPCThreadState.h> 24 #include <binder/IServiceManager.h> 25 26 #include <keystore/keystore.h> 27 28 using namespace android; 29 using namespace keystore; 30 31 static const char* responses[] = { 32 NULL, 33 /* [NO_ERROR] = */ "No error", 34 /* [LOCKED] = */ "Locked", 35 /* [UNINITIALIZED] = */ "Uninitialized", 36 /* [SYSTEM_ERROR] = */ "System error", 37 /* [PROTOCOL_ERROR] = */ "Protocol error", 38 /* [PERMISSION_DENIED] = */ "Permission denied", 39 /* [KEY_NOT_FOUND] = */ "Key not found", 40 /* [VALUE_CORRUPTED] = */ "Value corrupted", 41 /* [UNDEFINED_ACTION] = */ "Undefined action", 42 /* [WRONG_PASSWORD] = */ "Wrong password (last chance)", 43 /* [WRONG_PASSWORD + 1] = */ "Wrong password (2 tries left)", 44 /* [WRONG_PASSWORD + 2] = */ "Wrong password (3 tries left)", 45 /* [WRONG_PASSWORD + 3] = */ "Wrong password (4 tries left)", 46 }; 47 48 #define NO_ARG_INT_RETURN(cmd) \ 49 do { \ 50 if (strcmp(argv[1], #cmd) == 0) { \ 51 int32_t ret = service->cmd(); \ 52 if (ret < 0) { \ 53 fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \ 54 return 1; \ 55 } else { \ 56 printf(#cmd ": %s (%d)\n", responses[ret], ret); \ 57 return 0; \ 58 } \ 59 } \ 60 } while (0) 61 62 #define SINGLE_ARG_INT_RETURN(cmd) \ 63 do { \ 64 if (strcmp(argv[1], #cmd) == 0) { \ 65 if (argc < 3) { \ 66 fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \ 67 return 1; \ 68 } \ 69 int32_t ret = service->cmd(String16(argv[2])); \ 70 if (ret < 0) { \ 71 fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \ 72 return 1; \ 73 } else { \ 74 printf(#cmd ": %s (%d)\n", responses[ret], ret); \ 75 return 0; \ 76 } \ 77 } \ 78 } while (0) 79 80 #define SINGLE_INT_ARG_INT_RETURN(cmd) \ 81 do { \ 82 if (strcmp(argv[1], #cmd) == 0) { \ 83 if (argc < 3) { \ 84 fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \ 85 return 1; \ 86 } \ 87 int32_t ret = service->cmd(atoi(argv[2])); \ 88 if (ret < 0) { \ 89 fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \ 90 return 1; \ 91 } else { \ 92 printf(#cmd ": %s (%d)\n", responses[ret], ret); \ 93 return 0; \ 94 } \ 95 } \ 96 } while (0) 97 98 #define SINGLE_ARG_PLUS_UID_INT_RETURN(cmd) \ 99 do { \ 100 if (strcmp(argv[1], #cmd) == 0) { \ 101 if (argc < 3) { \ 102 fprintf(stderr, "Usage: %s " #cmd " <name> <uid>\n", argv[0]); \ 103 return 1; \ 104 } \ 105 int uid = -1; \ 106 if (argc > 3) { \ 107 uid = atoi(argv[3]); \ 108 fprintf(stderr, "Running as uid %d\n", uid); \ 109 } \ 110 int32_t ret = service->cmd(String16(argv[2]), uid); \ 111 if (ret < 0) { \ 112 fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \ 113 return 1; \ 114 } else { \ 115 printf(#cmd ": %s (%d)\n", responses[ret], ret); \ 116 return 0; \ 117 } \ 118 } \ 119 } while (0) 120 121 #define SINGLE_ARG_PLUS_UID_DATA_RETURN(cmd) \ 122 do { \ 123 if (strcmp(argv[1], #cmd) == 0) { \ 124 if (argc < 3) { \ 125 fprintf(stderr, "Usage: %s " #cmd " <name> <uid>\n", argv[0]); \ 126 return 1; \ 127 } \ 128 hidl_vec<uint8_t> data; \ 129 int uid = -1; \ 130 if (argc > 3) { \ 131 uid = atoi(argv[3]); \ 132 fprintf(stderr, "Running as uid %d\n", uid); \ 133 } \ 134 int32_t ret = service->cmd(String16(argv[2]), uid, &data); \ 135 if (ret < 0) { \ 136 fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \ 137 return 1; \ 138 } else if (ret != ::NO_ERROR) { \ 139 fprintf(stderr, "%s: " #cmd ": %s (%d)\n", argv[0], responses[ret], ret); \ 140 return 1; \ 141 } else { \ 142 fwrite(&data[0], data.size(), 1, stdout); \ 143 fflush(stdout); \ 144 return 0; \ 145 } \ 146 } \ 147 } while (0) 148 149 #define STING_ARG_DATA_STDIN_INT_RETURN(cmd) \ 150 do { \ 151 if (strcmp(argv[1], #cmd) == 0) { \ 152 if (argc < 3) { \ 153 fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \ 154 return 1; \ 155 } \ 156 uint8_t* data; \ 157 size_t dataSize; \ 158 read_input(&data, &dataSize); \ 159 int32_t ret = service->cmd(String16(argv[2]), data, dataSize); \ 160 if (ret < 0) { \ 161 fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \ 162 return 1; \ 163 } else { \ 164 printf(#cmd ": %s (%d)\n", responses[ret], ret); \ 165 return 0; \ 166 } \ 167 } \ 168 } while (0) 169 170 #define SINGLE_ARG_DATA_RETURN(cmd) \ 171 do { \ 172 if (strcmp(argv[1], #cmd) == 0) { \ 173 if (argc < 3) { \ 174 fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \ 175 return 1; \ 176 } \ 177 hidl_vec<uint8_t> data; \ 178 int32_t ret = service->cmd(String16(argv[2]), &data); \ 179 if (ret < 0) { \ 180 fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \ 181 return 1; \ 182 } else if (ret != ::NO_ERROR) { \ 183 fprintf(stderr, "%s: " #cmd ": %s (%d)\n", argv[0], responses[ret], ret); \ 184 return 1; \ 185 } else { \ 186 fwrite(&data[0], data.size(), 1, stdout); \ 187 fflush(stdout); \ 188 return 0; \ 189 } \ 190 } \ 191 } while (0) 192 193 static int list(const sp<IKeystoreService>& service, const String16& name, int uid) { 194 Vector<String16> matches; 195 int32_t ret = service->list(name, uid, &matches); 196 if (ret < 0) { 197 fprintf(stderr, "list: could not connect: %d\n", ret); 198 return 1; 199 } else if (ret != ::NO_ERROR) { 200 fprintf(stderr, "list: %s (%d)\n", responses[ret], ret); 201 return 1; 202 } else { 203 Vector<String16>::const_iterator it = matches.begin(); 204 for (; it != matches.end(); ++it) { 205 printf("%s\n", String8(*it).string()); 206 } 207 return 0; 208 } 209 } 210 211 int main(int argc, char* argv[]) 212 { 213 if (argc < 2) { 214 fprintf(stderr, "Usage: %s action [parameter ...]\n", argv[0]); 215 return 1; 216 } 217 218 sp<IServiceManager> sm = defaultServiceManager(); 219 sp<IBinder> binder = sm->getService(String16("android.security.keystore")); 220 sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder); 221 222 if (service == NULL) { 223 fprintf(stderr, "%s: error: could not connect to keystore service\n", argv[0]); 224 return 1; 225 } 226 227 /* 228 * All the commands should return a value 229 */ 230 231 SINGLE_INT_ARG_INT_RETURN(getState); 232 233 SINGLE_ARG_PLUS_UID_DATA_RETURN(get); 234 235 // TODO: insert 236 237 SINGLE_ARG_PLUS_UID_INT_RETURN(del); 238 239 SINGLE_ARG_PLUS_UID_INT_RETURN(exist); 240 241 if (strcmp(argv[1], "list") == 0) { 242 return list(service, argc < 3 ? String16("") : String16(argv[2]), 243 argc < 4 ? -1 : atoi(argv[3])); 244 } 245 246 NO_ARG_INT_RETURN(reset); 247 248 // TODO: notifyUserPasswordChanged 249 250 SINGLE_INT_ARG_INT_RETURN(lock); 251 252 // TODO: unlock 253 254 SINGLE_INT_ARG_INT_RETURN(isEmpty); 255 256 // TODO: generate 257 258 SINGLE_ARG_DATA_RETURN(get_pubkey); 259 260 // TODO: grant 261 262 // TODO: ungrant 263 264 // TODO: getmtime 265 266 fprintf(stderr, "%s: unknown command: %s\n", argv[0], argv[1]); 267 return 1; 268 } 269