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 * Load a single secret for ids over VICI
270 static bool load_secret(vici_conn_t
*conn
, char *type
, char *owners
,
271 char *value
, bool raw
)
273 enumerator_t
*enumerator
;
279 req
= vici_begin("load-shared");
281 vici_add_key_valuef(req
, "type", "%s", type
);
282 vici_begin_list(req
, "owners");
283 enumerator
= enumerator_create_token(owners
, " ", " ");
284 while (enumerator
->enumerate(enumerator
, &owners
))
286 vici_add_list_itemf(req
, "%s", owners
);
288 enumerator
->destroy(enumerator
);
291 if (strcasepfx(value
, "0x"))
293 data
= chunk_from_hex(chunk_from_str(value
+ 2), NULL
);
295 else if (strcasepfx(value
, "0s"))
297 data
= chunk_from_base64(chunk_from_str(value
+ 2), NULL
);
301 data
= chunk_clone(chunk_from_str(value
));
303 vici_add_key_value(req
, "data", data
.ptr
, data
.len
);
306 res
= vici_submit(req
, conn
);
309 fprintf(stderr
, "load-shared request failed: %s\n", strerror(errno
));
314 vici_dump(res
, "load-shared reply", stdout
);
316 else if (!streq(vici_find_str(res
, "no", "success"), "yes"))
318 fprintf(stderr
, "loading shared secret failed: %s\n",
319 vici_find_str(res
, "", "errmsg"));
327 * Load secrets from settings section
329 static void load_secrets(vici_conn_t
*conn
, settings_t
*cfg
,
330 char *section
, bool raw
)
332 enumerator_t
*enumerator
;
333 char buf
[64], *key
, *value
;
335 snprintf(buf
, sizeof(buf
), "secrets.%s", section
);
336 enumerator
= cfg
->create_key_value_enumerator(cfg
, buf
);
337 while (enumerator
->enumerate(enumerator
, &key
, &value
))
339 load_secret(conn
, section
, key
, value
, raw
);
341 enumerator
->destroy(enumerator
);
345 * Clear all currently loaded credentials
347 static bool clear_creds(vici_conn_t
*conn
, bool raw
)
351 res
= vici_submit(vici_begin("clear-creds"), conn
);
354 fprintf(stderr
, "clear-creds request failed: %s\n", strerror(errno
));
359 vici_dump(res
, "clear-creds reply", stdout
);
365 static int load_creds(vici_conn_t
*conn
)
367 bool raw
= FALSE
, clear
= FALSE
, noprompt
= FALSE
;
368 enumerator_t
*enumerator
;
374 switch (command_getopt(&arg
))
377 return command_usage(NULL
);
390 return command_usage("invalid --load-creds option");
397 if (!clear_creds(conn
, raw
))
403 load_certs(conn
, raw
, "x509", SWANCTL_X509DIR
);
404 load_certs(conn
, raw
, "x509ca", SWANCTL_X509CADIR
);
405 load_certs(conn
, raw
, "x509aa", SWANCTL_X509AADIR
);
406 load_certs(conn
, raw
, "x509crl", SWANCTL_X509CRLDIR
);
407 load_certs(conn
, raw
, "x509ac", SWANCTL_X509ACDIR
);
409 load_keys(conn
, raw
, noprompt
, "rsa", SWANCTL_RSADIR
);
410 load_keys(conn
, raw
, noprompt
, "ecdsa", SWANCTL_ECDSADIR
);
411 load_keys(conn
, raw
, noprompt
, "any", SWANCTL_PKCS8DIR
);
413 cfg
= settings_create(SWANCTL_CONF
);
416 fprintf(stderr
, "parsing '%s' failed\n", SWANCTL_CONF
);
420 enumerator
= cfg
->create_section_enumerator(cfg
, "secrets");
421 while (enumerator
->enumerate(enumerator
, §ion
))
423 load_secrets(conn
, cfg
, section
, raw
);
425 enumerator
->destroy(enumerator
);
433 * Register the command.
435 static void __attribute__ ((constructor
))reg()
437 command_register((command_t
) {
438 load_creds
, 's', "load-creds", "(re-)load credentials",
441 {"help", 'h', 0, "show usage information"},
442 {"clear", 'c', 0, "clear previously loaded credentials"},
443 {"noprompt", 'n', 0, "do not prompt for passwords"},
444 {"raw", 'r', 0, "dump raw response message"},