2 * Copyright (C) 2014 Martin Willi
3 * Copyright (C) 2014 revosec AG
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 #include <credentials/sets/callback_cred.h>
28 * Load a single certificate over vici
30 static bool load_cert(vici_conn_t
*conn
, bool raw
, char *dir
,
31 char *type
, chunk_t data
)
37 req
= vici_begin("load-cert");
39 vici_add_key_valuef(req
, "type", "%s", type
);
40 vici_add_key_value(req
, "data", data
.ptr
, data
.len
);
42 res
= vici_submit(req
, conn
);
45 fprintf(stderr
, "load-cert request failed: %s\n", strerror(errno
));
50 vici_dump(res
, "load-cert reply", stdout
);
52 else if (!streq(vici_find_str(res
, "no", "success"), "yes"))
54 fprintf(stderr
, "loading '%s' failed: %s\n",
55 dir
, vici_find_str(res
, "", "errmsg"));
63 * Load certficiates from a directory
65 static void load_certs(vici_conn_t
*conn
, bool raw
, char *type
, char *dir
)
67 enumerator_t
*enumerator
;
72 enumerator
= enumerator_create_directory(dir
);
75 while (enumerator
->enumerate(enumerator
, NULL
, &path
, &st
))
77 if (S_ISREG(st
.st_mode
))
79 map
= chunk_map(path
, FALSE
);
82 load_cert(conn
, raw
, path
, type
, *map
);
87 fprintf(stderr
, "mapping '%s' failed: %s, skipped\n",
88 path
, strerror(errno
));
92 enumerator
->destroy(enumerator
);
97 * Load a single private key over vici
99 static bool load_key(vici_conn_t
*conn
, bool raw
, char *dir
,
100 char *type
, chunk_t data
)
106 req
= vici_begin("load-key");
108 vici_add_key_valuef(req
, "type", "%s", type
);
109 vici_add_key_value(req
, "data", data
.ptr
, data
.len
);
111 res
= vici_submit(req
, conn
);
114 fprintf(stderr
, "load-key request failed: %s\n", strerror(errno
));
119 vici_dump(res
, "load-key reply", stdout
);
121 else if (!streq(vici_find_str(res
, "no", "success"), "yes"))
123 fprintf(stderr
, "loading '%s' failed: %s\n",
124 dir
, vici_find_str(res
, "", "errmsg"));
132 * Callback function to prompt for private key passwords
134 CALLBACK(password_cb
, shared_key_t
*,
135 char *prompt
, shared_key_type_t type
,
136 identification_t
*me
, identification_t
*other
,
137 id_match_t
*match_me
, id_match_t
*match_other
)
141 if (type
!= SHARED_PRIVATE_KEY_PASS
)
145 pwd
= getpass(prompt
);
146 if (!pwd
|| strlen(pwd
) == 0)
152 *match_me
= ID_MATCH_PERFECT
;
156 *match_other
= ID_MATCH_PERFECT
;
158 return shared_key_create(type
, chunk_clone(chunk_from_str(pwd
)));
162 * Try to parse a potentially encrypted private key
164 static private_key_t
* decrypt_key(char *name
, char *type
, chunk_t encoding
)
166 key_type_t kt
= KEY_ANY
;
167 private_key_t
*private;
171 if (streq(type
, "rsa"))
175 else if (streq(type
, "ecdsa"))
180 snprintf(buf
, sizeof(buf
), "Password for '%s': ", name
);
182 cb
= callback_cred_create_shared(password_cb
, buf
);
183 lib
->credmgr
->add_set(lib
->credmgr
, &cb
->set
);
185 private = lib
->creds
->create(lib
->creds
, CRED_PRIVATE_KEY
, kt
,
186 BUILD_BLOB_PEM
, encoding
, BUILD_END
);
188 lib
->credmgr
->remove_set(lib
->credmgr
, &cb
->set
);
195 * Try to decrypt and load a private key
197 static bool load_encrypted_key(vici_conn_t
*conn
, bool raw
,
198 char *rel
, char *path
, char *type
, chunk_t data
)
200 private_key_t
*private;
204 private = decrypt_key(rel
, type
, data
);
207 if (private->get_encoding(private, PRIVKEY_ASN1_DER
,
210 switch (private->get_type(private))
213 loaded
= load_key(conn
, raw
, path
, "rsa", encoding
);
216 loaded
= load_key(conn
, raw
, path
, "ecdsa", encoding
);
221 chunk_clear(&encoding
);
223 private->destroy(private);
229 * Load private keys from a directory
231 static void load_keys(vici_conn_t
*conn
, bool raw
, bool noprompt
,
232 char *type
, char *dir
)
234 enumerator_t
*enumerator
;
239 enumerator
= enumerator_create_directory(dir
);
242 while (enumerator
->enumerate(enumerator
, &rel
, &path
, &st
))
244 if (S_ISREG(st
.st_mode
))
246 map
= chunk_map(path
, FALSE
);
250 !load_encrypted_key(conn
, raw
, rel
, path
, type
, *map
))
252 load_key(conn
, raw
, path
, type
, *map
);
258 fprintf(stderr
, "mapping '%s' failed: %s, skipped\n",
259 path
, strerror(errno
));
263 enumerator
->destroy(enumerator
);
268 * Clear all currently loaded credentials
270 static bool clear_creds(vici_conn_t
*conn
, bool raw
)
274 res
= vici_submit(vici_begin("clear-creds"), conn
);
277 fprintf(stderr
, "clear-creds request failed: %s\n", strerror(errno
));
282 vici_dump(res
, "clear-creds reply", stdout
);
288 static int load_creds(vici_conn_t
*conn
)
290 bool raw
= FALSE
, clear
= FALSE
, noprompt
= FALSE
;
295 switch (command_getopt(&arg
))
298 return command_usage(NULL
);
311 return command_usage("invalid --load-creds option");
318 if (!clear_creds(conn
, raw
))
324 load_certs(conn
, raw
, "x509", SWANCTL_X509DIR
);
325 load_certs(conn
, raw
, "x509ca", SWANCTL_X509CADIR
);
326 load_certs(conn
, raw
, "x509aa", SWANCTL_X509AADIR
);
327 load_certs(conn
, raw
, "x509crl", SWANCTL_X509CRLDIR
);
328 load_certs(conn
, raw
, "x509ac", SWANCTL_X509ACDIR
);
330 load_keys(conn
, raw
, noprompt
, "rsa", SWANCTL_RSADIR
);
331 load_keys(conn
, raw
, noprompt
, "ecdsa", SWANCTL_ECDSADIR
);
332 load_keys(conn
, raw
, noprompt
, "any", SWANCTL_PKCS8DIR
);
338 * Register the command.
340 static void __attribute__ ((constructor
))reg()
342 command_register((command_t
) {
343 load_creds
, 's', "load-creds", "(re-)load credentials",
346 {"help", 'h', 0, "show usage information"},
347 {"clear", 'c', 0, "clear previously loaded credentials"},
348 {"noprompt", 'n', 0, "do not prompt for passwords"},
349 {"raw", 'r', 0, "dump raw response message"},