blob: 17dd060ac56a2dcc18bc43f51d2b38dabc3c2b97 [file] [log] [blame]
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +08001/*
Chung-yih Wang4c404202009-06-17 01:29:21 +08002** Copyright 2009, The Android Open Source Project
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +08003**
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 "keystore.h"
18
19static DIR *open_keystore(const char *dir)
20{
21 DIR *d;
22 if ((d = opendir(dir)) == NULL) {
23 if (mkdir(dir, 0770) < 0) {
24 LOGE("cannot create dir '%s': %s\n", dir, strerror(errno));
25 unlink(dir);
26 return NULL;
27 }
28 d = open_keystore(dir);
29 }
30 return d;
31}
32
Chung-yih Wang4c404202009-06-17 01:29:21 +080033static int list_files(const char *dir, char reply[REPLY_MAX])
34{
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +080035 struct dirent *de;
36 DIR *d;
37
38 if ((d = open_keystore(dir)) == NULL) {
39 return -1;
40 }
41 reply[0]=0;
42 while ((de = readdir(d))) {
Chung-yih Wang4c404202009-06-17 01:29:21 +080043 if (de->d_type != DT_DIR) continue;
44 if ((strcmp(DOT, de->d_name) == 0) ||
45 (strcmp(DOTDOT, de->d_name) == 0)) continue;
Chung-yih Wang8fcbada2009-06-10 18:45:14 +080046 if (reply[0] != 0) strlcat(reply, " ", REPLY_MAX);
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +080047 if (strlcat(reply, de->d_name, REPLY_MAX) >= REPLY_MAX) {
48 LOGE("reply is too long(too many files under '%s'\n", dir);
49 return -1;
50 }
51 }
52 closedir(d);
53 return 0;
54}
55
Chung-yih Wang4c404202009-06-17 01:29:21 +080056static int copy_keyfile(const char *src, int src_type, const char *dstfile) {
57 int srcfd = -1, dstfd;
58 char buf[REPLY_MAX];
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +080059
Chung-yih Wang4c404202009-06-17 01:29:21 +080060 if ((src_type == IS_FILE) && (srcfd = open(src, O_RDONLY)) == -1) {
61 LOGE("Cannot open the original file '%s'\n", src);
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +080062 return -1;
63 }
64 if ((dstfd = open(dstfile, O_CREAT|O_RDWR)) == -1) {
65 LOGE("Cannot open the destination file '%s'\n", dstfile);
66 return -1;
67 }
Chung-yih Wang4c404202009-06-17 01:29:21 +080068 if (src_type == IS_FILE) {
69 int length;
70 while((length = read(srcfd, buf, REPLY_MAX)) > 0) {
71 write(dstfd, buf, length);
72 }
73 } else {
74 write(dstfd, src, strlen(src));
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +080075 }
76 close(srcfd);
77 close(dstfd);
78 chmod(dstfile, 0440);
79 return 0;
80}
81
Chung-yih Wang4c404202009-06-17 01:29:21 +080082static int install_key(const char *path, const char *certname, const char *src,
83 int src_is_file, char *dstfile)
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +080084{
85 struct dirent *de;
Chung-yih Wang4c404202009-06-17 01:29:21 +080086 char fullpath[KEYNAME_LENGTH];
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +080087 DIR *d;
88
Chung-yih Wang4c404202009-06-17 01:29:21 +080089 if (snprintf(fullpath, sizeof(fullpath), "%s/%s/", path, certname)
90 >= KEYNAME_LENGTH) {
91 LOGE("cert name '%s' is too long.\n", certname);
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +080092 return -1;
93 }
Chung-yih Wang4c404202009-06-17 01:29:21 +080094
95 if ((d = open_keystore(fullpath)) == NULL) {
96 LOGE("Can not open the keystore '%s'\n", fullpath);
97 return -1;
98 }
99 closedir(d);
100 if (strlcat(fullpath, dstfile, KEYNAME_LENGTH) >= KEYNAME_LENGTH) {
101 LOGE("cert name '%s' is too long.\n", certname);
102 return -1;
103 }
104 return copy_keyfile(src, src_is_file, fullpath);
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +0800105}
106
Chung-yih Wang4c404202009-06-17 01:29:21 +0800107static int get_key(const char *path, const char *keyname, const char *file,
108 char reply[REPLY_MAX])
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +0800109{
Chung-yih Wang4c404202009-06-17 01:29:21 +0800110 struct dirent *de;
111 char filename[KEYNAME_LENGTH];
112 int fd;
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +0800113
Chung-yih Wang4c404202009-06-17 01:29:21 +0800114 if (snprintf(filename, sizeof(filename), "%s/%s/%s", path, keyname, file)
115 >= KEYNAME_LENGTH) {
116 LOGE("cert name '%s' is too long.\n", keyname);
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +0800117 return -1;
118 }
Chung-yih Wang4c404202009-06-17 01:29:21 +0800119
120 if ((fd = open(filename, O_RDONLY)) == -1) {
121 return -1;
122 }
123 close(fd);
124 strlcpy(reply, filename, REPLY_MAX);
125 return 0;
126}
127
128static int remove_key(const char *dir, const char *key)
129{
130 char dstfile[KEYNAME_LENGTH];
131 char *keyfile[4] = { USER_KEY, USER_P12_CERT, USER_CERTIFICATE,
132 CA_CERTIFICATE };
133 int i, count = 0;
134
135 for ( i = 0 ; i < 4 ; i++) {
136 if (snprintf(dstfile, KEYNAME_LENGTH, "%s/%s/%s", dir, key, keyfile[i])
137 >= KEYNAME_LENGTH) {
138 LOGE("keyname is too long '%s'\n", key);
139 return -1;
140 }
141 if (unlink(dstfile) == 0) count++;
142 }
143
144 if (count == 0) {
145 LOGE("can not clean up '%s' keys or not exist\n", key);
146 return -1;
147 }
148
149 snprintf(dstfile, KEYNAME_LENGTH, "%s/%s", dir, key);
150 if (rmdir(dstfile)) {
151 LOGE("can not clean up '%s' directory\n", key);
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +0800152 return -1;
153 }
154 return 0;
155}
156
Chung-yih Wang4c404202009-06-17 01:29:21 +0800157int list_user_certs(char reply[REPLY_MAX])
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +0800158{
159 return list_files(CERTS_DIR, reply);
160}
161
Chung-yih Wang4c404202009-06-17 01:29:21 +0800162int list_ca_certs(char reply[REPLY_MAX])
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +0800163{
Chung-yih Wang4c404202009-06-17 01:29:21 +0800164 return list_files(CACERTS_DIR, reply);
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +0800165}
166
Chung-yih Wang4c404202009-06-17 01:29:21 +0800167int install_user_cert(const char *keyname, const char *cert, const char *key)
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +0800168{
Chung-yih Wang4c404202009-06-17 01:29:21 +0800169 if (install_key(CERTS_DIR, keyname, cert, IS_FILE, USER_CERTIFICATE) == 0) {
170 return install_key(CERTS_DIR, keyname, key, IS_FILE, USER_KEY);
171 }
172 return -1;
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +0800173}
174
Chung-yih Wang4c404202009-06-17 01:29:21 +0800175int install_ca_cert(const char *keyname, const char *certfile)
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +0800176{
Chung-yih Wang4c404202009-06-17 01:29:21 +0800177 return install_key(CACERTS_DIR, keyname, certfile, IS_FILE, CA_CERTIFICATE);
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +0800178}
179
Chung-yih Wang4c404202009-06-17 01:29:21 +0800180int install_p12_cert(const char *keyname, const char *certfile)
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +0800181{
Chung-yih Wang4c404202009-06-17 01:29:21 +0800182 return install_key(CERTS_DIR, keyname, certfile, IS_FILE, USER_P12_CERT);
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +0800183}
184
Chung-yih Wang4c404202009-06-17 01:29:21 +0800185int add_ca_cert(const char *keyname, const char *certificate)
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +0800186{
Chung-yih Wang4c404202009-06-17 01:29:21 +0800187 return install_key(CACERTS_DIR, keyname, certificate, IS_CONTENT,
188 CA_CERTIFICATE);
189}
190
191int add_user_cert(const char *keyname, const char *certificate)
192{
193 return install_key(CERTS_DIR, keyname, certificate, IS_CONTENT,
194 USER_CERTIFICATE);
195}
196
197int add_user_key(const char *keyname, const char *key)
198{
199 return install_key(CERTS_DIR, keyname, key, IS_CONTENT, USER_KEY);
200}
201
202int get_ca_cert(const char *keyname, char reply[REPLY_MAX])
203{
204 return get_key(CACERTS_DIR, keyname, CA_CERTIFICATE, reply);
205}
206
207int get_user_cert(const char *keyname, char reply[REPLY_MAX])
208{
209 return get_key(CERTS_DIR, keyname, USER_CERTIFICATE, reply);
210}
211
212int get_user_key(const char *keyname, char reply[REPLY_MAX])
213{
214 if(get_key(CERTS_DIR, keyname, USER_KEY, reply))
215 return get_key(CERTS_DIR, keyname, USER_P12_CERT, reply);
216 return 0;
217}
218
219int remove_user_cert(const char *key)
220{
221 return remove_key(CERTS_DIR, key);
222}
223
224int remove_ca_cert(const char *key)
225{
226 return remove_key(CACERTS_DIR, key);
Chung-yih Wanga92d5dc2009-06-08 16:34:54 +0800227}