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
28using namespace android;
29
30static const char* responses[] = {
31    NULL,
32    /* [NO_ERROR]           = */ "No error",
33    /* [LOCKED]             = */ "Locked",
34    /* [UNINITIALIZED]      = */ "Uninitialized",
35    /* [SYSTEM_ERROR]       = */ "System error",
36    /* [PROTOCOL_ERROR]     = */ "Protocol error",
37    /* [PERMISSION_DENIED]  = */ "Permission denied",
38    /* [KEY_NOT_FOUND]      = */ "Key not found",
39    /* [VALUE_CORRUPTED]    = */ "Value corrupted",
40    /* [UNDEFINED_ACTION]   = */ "Undefined action",
41    /* [WRONG_PASSWORD]     = */ "Wrong password (last chance)",
42    /* [WRONG_PASSWORD + 1] = */ "Wrong password (2 tries left)",
43    /* [WRONG_PASSWORD + 2] = */ "Wrong password (3 tries left)",
44    /* [WRONG_PASSWORD + 3] = */ "Wrong password (4 tries left)",
45};
46
47#define NO_ARG_INT_RETURN(cmd) \
48    do { \
49        if (strcmp(argv[1], #cmd) == 0) { \
50            int32_t ret = service->cmd(); \
51            if (ret < 0) { \
52                fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
53                return 1; \
54            } else { \
55                printf(#cmd ": %s (%d)\n", responses[ret], ret); \
56                return 0; \
57            } \
58        } \
59    } while (0)
60
61#define SINGLE_ARG_INT_RETURN(cmd) \
62    do { \
63        if (strcmp(argv[1], #cmd) == 0) { \
64            if (argc < 3) { \
65                fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \
66                return 1; \
67            } \
68            int32_t ret = service->cmd(String16(argv[2])); \
69            if (ret < 0) { \
70                fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
71                return 1; \
72            } else { \
73                printf(#cmd ": %s (%d)\n", responses[ret], ret); \
74                return 0; \
75            } \
76        } \
77    } while (0)
78
79#define SINGLE_ARG_PLUS_UID_INT_RETURN(cmd) \
80    do { \
81        if (strcmp(argv[1], #cmd) == 0) { \
82            if (argc < 3) { \
83                fprintf(stderr, "Usage: %s " #cmd " <name> <uid>\n", argv[0]); \
84                return 1; \
85            } \
86            int uid = -1; \
87            if (argc > 3) { \
88                uid = atoi(argv[3]); \
89                fprintf(stderr, "Running as uid %d\n", uid); \
90            } \
91            int32_t ret = service->cmd(String16(argv[2]), uid); \
92            if (ret < 0) { \
93                fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
94                return 1; \
95            } else { \
96                printf(#cmd ": %s (%d)\n", responses[ret], ret); \
97                return 0; \
98            } \
99        } \
100    } while (0)
101
102#define STING_ARG_DATA_STDIN_INT_RETURN(cmd) \
103    do { \
104        if (strcmp(argv[1], #cmd) == 0) { \
105            if (argc < 3) { \
106                fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \
107                return 1; \
108            } \
109            uint8_t* data; \
110            size_t dataSize; \
111            read_input(&data, &dataSize); \
112            int32_t ret = service->cmd(String16(argv[2]), data, dataSize); \
113            if (ret < 0) { \
114                fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
115                return 1; \
116            } else { \
117                printf(#cmd ": %s (%d)\n", responses[ret], ret); \
118                return 0; \
119            } \
120        } \
121    } while (0)
122
123#define SINGLE_ARG_DATA_RETURN(cmd) \
124    do { \
125        if (strcmp(argv[1], #cmd) == 0) { \
126            if (argc < 3) { \
127                fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \
128                return 1; \
129            } \
130            uint8_t* data; \
131            size_t dataSize; \
132            int32_t ret = service->cmd(String16(argv[2]), &data, &dataSize); \
133            if (ret < 0) { \
134                fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
135                return 1; \
136            } else if (ret != ::NO_ERROR) { \
137                fprintf(stderr, "%s: " #cmd ": %s (%d)\n", argv[0], responses[ret], ret); \
138                return 1; \
139            } else { \
140                fwrite(data, dataSize, 1, stdout); \
141                fflush(stdout); \
142                free(data); \
143                return 0; \
144            } \
145        } \
146    } while (0)
147
148static int saw(sp<IKeystoreService> service, const String16& name, int uid) {
149    Vector<String16> matches;
150    int32_t ret = service->saw(name, uid, &matches);
151    if (ret < 0) {
152        fprintf(stderr, "saw: could not connect: %d\n", ret);
153        return 1;
154    } else if (ret != ::NO_ERROR) {
155        fprintf(stderr, "saw: %s (%d)\n", responses[ret], ret);
156        return 1;
157    } else {
158        Vector<String16>::const_iterator it = matches.begin();
159        for (; it != matches.end(); ++it) {
160            printf("%s\n", String8(*it).string());
161        }
162        return 0;
163    }
164}
165
166int main(int argc, char* argv[])
167{
168    if (argc < 2) {
169        fprintf(stderr, "Usage: %s action [parameter ...]\n", argv[0]);
170        return 1;
171    }
172
173    sp<IServiceManager> sm = defaultServiceManager();
174    sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
175    sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
176
177    if (service == NULL) {
178        fprintf(stderr, "%s: error: could not connect to keystore service\n", argv[0]);
179        return 1;
180    }
181
182    /*
183     * All the commands should return a value
184     */
185
186    NO_ARG_INT_RETURN(test);
187
188    SINGLE_ARG_DATA_RETURN(get);
189
190    // TODO: insert
191
192    SINGLE_ARG_PLUS_UID_INT_RETURN(del);
193
194    SINGLE_ARG_PLUS_UID_INT_RETURN(exist);
195
196    if (strcmp(argv[1], "saw") == 0) {
197        return saw(service, argc < 3 ? String16("") : String16(argv[2]),
198                argc < 4 ? -1 : atoi(argv[3]));
199    }
200
201    NO_ARG_INT_RETURN(reset);
202
203    SINGLE_ARG_INT_RETURN(password);
204
205    NO_ARG_INT_RETURN(lock);
206
207    SINGLE_ARG_INT_RETURN(unlock);
208
209    NO_ARG_INT_RETURN(zero);
210
211    // TODO: generate
212
213    SINGLE_ARG_DATA_RETURN(get_pubkey);
214
215    SINGLE_ARG_PLUS_UID_INT_RETURN(del_key);
216
217    // TODO: grant
218
219    // TODO: ungrant
220
221    // TODO: getmtime
222
223    fprintf(stderr, "%s: unknown command: %s\n", argv[0], argv[1]);
224    return 1;
225}
226