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"));
60 printf("loaded %s certificate '%s'\n", type
, dir
);
67 * Load certficiates from a directory
69 static void load_certs(vici_conn_t
*conn
, bool raw
, char *type
, char *dir
)
71 enumerator_t
*enumerator
;
76 enumerator
= enumerator_create_directory(dir
);
79 while (enumerator
->enumerate(enumerator
, NULL
, &path
, &st
))
81 if (S_ISREG(st
.st_mode
))
83 map
= chunk_map(path
, FALSE
);
86 load_cert(conn
, raw
, path
, type
, *map
);
91 fprintf(stderr
, "mapping '%s' failed: %s, skipped\n",
92 path
, strerror(errno
));
96 enumerator
->destroy(enumerator
);
101 * Load a single private key over vici
103 static bool load_key(vici_conn_t
*conn
, bool raw
, char *dir
,
104 char *type
, chunk_t data
)
110 req
= vici_begin("load-key");
112 vici_add_key_valuef(req
, "type", "%s", type
);
113 vici_add_key_value(req
, "data", data
.ptr
, data
.len
);
115 res
= vici_submit(req
, conn
);
118 fprintf(stderr
, "load-key request failed: %s\n", strerror(errno
));
123 vici_dump(res
, "load-key reply", stdout
);
125 else if (!streq(vici_find_str(res
, "no", "success"), "yes"))
127 fprintf(stderr
, "loading '%s' failed: %s\n",
128 dir
, vici_find_str(res
, "", "errmsg"));
133 printf("loaded %s key '%s'\n", type
, dir
);
140 * Callback function to prompt for private key passwords
142 CALLBACK(password_cb
, shared_key_t
*,
143 char *prompt
, shared_key_type_t type
,
144 identification_t
*me
, identification_t
*other
,
145 id_match_t
*match_me
, id_match_t
*match_other
)
149 if (type
!= SHARED_PRIVATE_KEY_PASS
)
153 pwd
= getpass(prompt
);
154 if (!pwd
|| strlen(pwd
) == 0)
160 *match_me
= ID_MATCH_PERFECT
;
164 *match_other
= ID_MATCH_PERFECT
;
166 return shared_key_create(type
, chunk_clone(chunk_from_str(pwd
)));
170 * Try to parse a potentially encrypted private key
172 static private_key_t
* decrypt_key(char *name
, char *type
, chunk_t encoding
)
174 key_type_t kt
= KEY_ANY
;
175 private_key_t
*private;
179 if (streq(type
, "rsa"))
183 else if (streq(type
, "ecdsa"))
188 snprintf(buf
, sizeof(buf
), "Password for '%s': ", name
);
190 cb
= callback_cred_create_shared(password_cb
, buf
);
191 lib
->credmgr
->add_set(lib
->credmgr
, &cb
->set
);
193 private = lib
->creds
->create(lib
->creds
, CRED_PRIVATE_KEY
, kt
,
194 BUILD_BLOB_PEM
, encoding
, BUILD_END
);
196 lib
->credmgr
->remove_set(lib
->credmgr
, &cb
->set
);
203 * Try to decrypt and load a private key
205 static bool load_encrypted_key(vici_conn_t
*conn
, bool raw
,
206 char *rel
, char *path
, char *type
, chunk_t data
)
208 private_key_t
*private;
212 private = decrypt_key(rel
, type
, data
);
215 if (private->get_encoding(private, PRIVKEY_ASN1_DER
,
218 switch (private->get_type(private))
221 loaded
= load_key(conn
, raw
, path
, "rsa", encoding
);
224 loaded
= load_key(conn
, raw
, path
, "ecdsa", encoding
);
229 chunk_clear(&encoding
);
231 private->destroy(private);
237 * Load private keys from a directory
239 static void load_keys(vici_conn_t
*conn
, bool raw
, bool noprompt
,
240 char *type
, char *dir
)
242 enumerator_t
*enumerator
;
247 enumerator
= enumerator_create_directory(dir
);
250 while (enumerator
->enumerate(enumerator
, &rel
, &path
, &st
))
252 if (S_ISREG(st
.st_mode
))
254 map
= chunk_map(path
, FALSE
);
258 !load_encrypted_key(conn
, raw
, rel
, path
, type
, *map
))
260 load_key(conn
, raw
, path
, type
, *map
);
266 fprintf(stderr
, "mapping '%s' failed: %s, skipped\n",
267 path
, strerror(errno
));
271 enumerator
->destroy(enumerator
);
276 * Load a single secret for ids over VICI
278 static bool load_secret(vici_conn_t
*conn
, char *type
, char *owners
,
279 char *value
, bool raw
)
281 enumerator_t
*enumerator
;
288 req
= vici_begin("load-shared");
290 vici_add_key_valuef(req
, "type", "%s", type
);
291 vici_begin_list(req
, "owners");
292 enumerator
= enumerator_create_token(owners
, " ", " ");
293 while (enumerator
->enumerate(enumerator
, &owner
))
295 vici_add_list_itemf(req
, "%s", owner
);
297 enumerator
->destroy(enumerator
);
300 if (strcasepfx(value
, "0x"))
302 data
= chunk_from_hex(chunk_from_str(value
+ 2), NULL
);
304 else if (strcasepfx(value
, "0s"))
306 data
= chunk_from_base64(chunk_from_str(value
+ 2), NULL
);
310 data
= chunk_clone(chunk_from_str(value
));
312 vici_add_key_value(req
, "data", data
.ptr
, data
.len
);
315 res
= vici_submit(req
, conn
);
318 fprintf(stderr
, "load-shared request failed: %s\n", strerror(errno
));
323 vici_dump(res
, "load-shared reply", stdout
);
325 else if (!streq(vici_find_str(res
, "no", "success"), "yes"))
327 fprintf(stderr
, "loading shared secret failed: %s\n",
328 vici_find_str(res
, "", "errmsg"));
333 printf("loaded %s secret for: ", type
);
334 enumerator
= enumerator_create_token(owners
, " ", " ");
335 while (enumerator
->enumerate(enumerator
, &owner
))
337 printf("'%s' ", owner
);
339 enumerator
->destroy(enumerator
);
347 * Load secrets from settings section
349 static void load_secrets(vici_conn_t
*conn
, settings_t
*cfg
,
350 char *section
, bool raw
)
352 enumerator_t
*enumerator
;
353 char buf
[64], *key
, *value
;
355 snprintf(buf
, sizeof(buf
), "secrets.%s", section
);
356 enumerator
= cfg
->create_key_value_enumerator(cfg
, buf
);
357 while (enumerator
->enumerate(enumerator
, &key
, &value
))
359 load_secret(conn
, section
, key
, value
, raw
);
361 enumerator
->destroy(enumerator
);
365 * Clear all currently loaded credentials
367 static bool clear_creds(vici_conn_t
*conn
, bool raw
)
371 res
= vici_submit(vici_begin("clear-creds"), conn
);
374 fprintf(stderr
, "clear-creds request failed: %s\n", strerror(errno
));
379 vici_dump(res
, "clear-creds reply", stdout
);
385 static int load_creds(vici_conn_t
*conn
)
387 bool raw
= FALSE
, clear
= FALSE
, noprompt
= FALSE
;
388 enumerator_t
*enumerator
;
394 switch (command_getopt(&arg
))
397 return command_usage(NULL
);
410 return command_usage("invalid --load-creds option");
417 if (!clear_creds(conn
, raw
))
423 load_certs(conn
, raw
, "x509", SWANCTL_X509DIR
);
424 load_certs(conn
, raw
, "x509ca", SWANCTL_X509CADIR
);
425 load_certs(conn
, raw
, "x509aa", SWANCTL_X509AADIR
);
426 load_certs(conn
, raw
, "x509crl", SWANCTL_X509CRLDIR
);
427 load_certs(conn
, raw
, "x509ac", SWANCTL_X509ACDIR
);
429 load_keys(conn
, raw
, noprompt
, "rsa", SWANCTL_RSADIR
);
430 load_keys(conn
, raw
, noprompt
, "ecdsa", SWANCTL_ECDSADIR
);
431 load_keys(conn
, raw
, noprompt
, "any", SWANCTL_PKCS8DIR
);
433 cfg
= settings_create(SWANCTL_CONF
);
436 fprintf(stderr
, "parsing '%s' failed\n", SWANCTL_CONF
);
440 enumerator
= cfg
->create_section_enumerator(cfg
, "secrets");
441 while (enumerator
->enumerate(enumerator
, §ion
))
443 load_secrets(conn
, cfg
, section
, raw
);
445 enumerator
->destroy(enumerator
);
453 * Register the command.
455 static void __attribute__ ((constructor
))reg()
457 command_register((command_t
) {
458 load_creds
, 's', "load-creds", "(re-)load credentials",
461 {"help", 'h', 0, "show usage information"},
462 {"clear", 'c', 0, "clear previously loaded credentials"},
463 {"noprompt", 'n', 0, "do not prompt for passwords"},
464 {"raw", 'r', 0, "dump raw response message"},