charon-cmd: Request password for private keys
[strongswan.git] / src / charon-cmd / cmd / cmd_creds.c
1 /*
2 * Copyright (C) 2013 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * Copyright (C) 2013 Martin Willi
6 * Copyright (C) 2013 revosec AG
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
19 #include "cmd_creds.h"
20
21 #include <unistd.h>
22
23 #include <utils/debug.h>
24 #include <credentials/sets/mem_cred.h>
25 #include <credentials/sets/callback_cred.h>
26
27 typedef struct private_cmd_creds_t private_cmd_creds_t;
28
29 /**
30 * Private data of an cmd_creds_t object.
31 */
32 struct private_cmd_creds_t {
33
34 /**
35 * Public cmd_creds_t interface.
36 */
37 cmd_creds_t public;
38
39 /**
40 * Reused in-memory credential set
41 */
42 mem_cred_t *creds;
43
44 /**
45 * Callback credential set to get secrets
46 */
47 callback_cred_t *cb;
48
49 /**
50 * Already prompted for password?
51 */
52 bool prompted;
53
54 /**
55 * Path to ssh-agent socket
56 */
57 char *agent;
58
59 /**
60 * Local identity
61 */
62 char *identity;
63 };
64
65 /**
66 * Callback function to prompt for secret
67 */
68 static shared_key_t* callback_shared(private_cmd_creds_t *this,
69 shared_key_type_t type,
70 identification_t *me, identification_t *other,
71 id_match_t *match_me, id_match_t *match_other)
72 {
73 char *label, *pwd;
74
75 if (this->prompted)
76 {
77 return NULL;
78 }
79 switch (type)
80 {
81 case SHARED_EAP:
82 label = "EAP password: ";
83 break;
84 case SHARED_IKE:
85 label = "Preshared Key: ";
86 break;
87 case SHARED_PRIVATE_KEY_PASS:
88 label = "Password: ";
89 break;
90 default:
91 return NULL;
92 }
93 pwd = getpass(label);
94 if (!pwd || strlen(pwd) == 0)
95 {
96 return NULL;
97 }
98 this->prompted = TRUE;
99 *match_me = *match_other = ID_MATCH_PERFECT;
100 return shared_key_create(type, chunk_clone(chunk_from_str(pwd)));
101 }
102
103 /**
104 * Load a trusted certificate from path
105 */
106 static void load_cert(private_cmd_creds_t *this, char *path)
107 {
108 certificate_t *cert;
109
110 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
111 BUILD_FROM_FILE, path, BUILD_END);
112 if (!cert)
113 {
114 DBG1(DBG_CFG, "loading certificate from '%s' failed", path);
115 exit(1);
116 }
117 this->creds->add_cert(this->creds, TRUE, cert);
118 }
119
120 /**
121 * Load a private key of given kind from path
122 */
123 static void load_key(private_cmd_creds_t *this, key_type_t type, char *path)
124 {
125 private_key_t *privkey;
126
127 privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
128 BUILD_FROM_FILE, path, BUILD_END);
129 if (!privkey)
130 {
131 DBG1(DBG_CFG, "loading %N private key from '%s' failed",
132 key_type_names, type, path);
133 exit(1);
134 }
135 this->creds->add_key(this->creds, privkey);
136 }
137
138 /**
139 * Load a private and public key via ssh-agent
140 */
141 static void load_agent(private_cmd_creds_t *this)
142 {
143 private_key_t *privkey;
144 public_key_t *pubkey;
145 identification_t *id;
146 certificate_t *cert;
147
148 privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
149 BUILD_AGENT_SOCKET, this->agent, BUILD_END);
150 if (!privkey)
151 {
152 DBG1(DBG_CFG, "failed to load private key from ssh-agent");
153 exit(1);
154 }
155 pubkey = privkey->get_public_key(privkey);
156 if (!pubkey)
157 {
158 DBG1(DBG_CFG, "failed to load public key from ssh-agent");
159 privkey->destroy(privkey);
160 exit(1);
161 }
162 id = identification_create_from_string(this->identity);
163 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
164 CERT_TRUSTED_PUBKEY, BUILD_PUBLIC_KEY, pubkey,
165 BUILD_SUBJECT, id, BUILD_END);
166 pubkey->destroy(pubkey);
167 id->destroy(id);
168 if (!cert)
169 {
170 DBG1(DBG_CFG, "failed to create certificate for ssh-agent public key");
171 privkey->destroy(privkey);
172 exit(1);
173 }
174 this->creds->add_cert(this->creds, TRUE, cert);
175 this->creds->add_key(this->creds, privkey);
176 }
177
178 METHOD(cmd_creds_t, handle, bool,
179 private_cmd_creds_t *this, cmd_option_type_t opt, char *arg)
180 {
181 switch (opt)
182 {
183 case CMD_OPT_CERT:
184 load_cert(this, arg);
185 break;
186 case CMD_OPT_RSA:
187 load_key(this, KEY_RSA, arg);
188 break;
189 case CMD_OPT_IDENTITY:
190 this->identity = arg;
191 break;
192 case CMD_OPT_AGENT:
193 this->agent = arg ?: getenv("SSH_AUTH_SOCK");
194 if (!this->agent)
195 {
196 DBG1(DBG_CFG, "no ssh-agent socket defined");
197 exit(1);
198 }
199 break;
200 default:
201 return FALSE;
202 }
203 if (this->agent && this->identity)
204 {
205 load_agent(this);
206 /* only do this once */
207 this->agent = NULL;
208 }
209 return TRUE;
210 }
211
212 METHOD(cmd_creds_t, destroy, void,
213 private_cmd_creds_t *this)
214 {
215 lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
216 lib->credmgr->remove_set(lib->credmgr, &this->cb->set);
217 this->creds->destroy(this->creds);
218 this->cb->destroy(this->cb);
219 free(this);
220 }
221
222 /**
223 * See header
224 */
225 cmd_creds_t *cmd_creds_create()
226 {
227 private_cmd_creds_t *this;
228
229 INIT(this,
230 .public = {
231 .handle = _handle,
232 .destroy = _destroy,
233 },
234 .creds = mem_cred_create(),
235 );
236 this->cb = callback_cred_create_shared((void*)callback_shared, this);
237
238 lib->credmgr->add_set(lib->credmgr, &this->creds->set);
239 lib->credmgr->add_set(lib->credmgr, &this->cb->set);
240
241 return &this->public;
242 }