Version bump to 5.9.0dr1
[strongswan.git] / src / charon-cmd / cmd / cmd_creds.c
1 /*
2 * Copyright (C) 2013 Tobias Brunner
3 * HSR 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/containers/pkcs12.h>
26 #include <credentials/sets/callback_cred.h>
27
28 typedef struct private_cmd_creds_t private_cmd_creds_t;
29
30 /**
31 * Private data of an cmd_creds_t object.
32 */
33 struct private_cmd_creds_t {
34
35 /**
36 * Public cmd_creds_t interface.
37 */
38 cmd_creds_t public;
39
40 /**
41 * Reused in-memory credential set
42 */
43 mem_cred_t *creds;
44
45 /**
46 * Callback credential set to get secrets
47 */
48 callback_cred_t *cb;
49
50 /**
51 * Kind of secret we recently prompted
52 */
53 shared_key_type_t prompted;
54
55 /**
56 * Path to ssh-agent socket
57 */
58 char *agent;
59
60 /**
61 * Local identity
62 */
63 char *identity;
64 };
65
66 /**
67 * Callback function to prompt for secret
68 */
69 static shared_key_t* callback_shared(private_cmd_creds_t *this,
70 shared_key_type_t type,
71 identification_t *me, identification_t *other,
72 id_match_t *match_me, id_match_t *match_other)
73 {
74 shared_key_t *shared;
75 char *label, *pwd = NULL;
76
77 if (type == this->prompted)
78 {
79 return NULL;
80 }
81 switch (type)
82 {
83 case SHARED_EAP:
84 label = "EAP password: ";
85 break;
86 case SHARED_IKE:
87 label = "Preshared Key: ";
88 break;
89 case SHARED_PRIVATE_KEY_PASS:
90 label = "Password: ";
91 break;
92 case SHARED_PIN:
93 label = "PIN: ";
94 break;
95 default:
96 return NULL;
97 }
98 #ifdef HAVE_GETPASS
99 pwd = getpass(label);
100 #endif
101 if (!pwd || strlen(pwd) == 0)
102 {
103 return NULL;
104 }
105 this->prompted = type;
106 if (match_me)
107 {
108 *match_me = ID_MATCH_PERFECT;
109 }
110 if (match_other)
111 {
112 *match_other = ID_MATCH_PERFECT;
113 }
114 shared = shared_key_create(type, chunk_clone(chunk_from_str(pwd)));
115 /* cache password in case it is required more than once */
116 this->creds->add_shared(this->creds, shared, NULL);
117 return shared->get_ref(shared);
118 }
119
120 /**
121 * Load a trusted certificate from path
122 */
123 static void load_cert(private_cmd_creds_t *this, char *path)
124 {
125 certificate_t *cert;
126
127 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
128 BUILD_FROM_FILE, path, BUILD_END);
129 if (!cert)
130 {
131 DBG1(DBG_CFG, "loading certificate from '%s' failed", path);
132 exit(1);
133 }
134 this->creds->add_cert(this->creds, TRUE, cert);
135 }
136
137 /**
138 * Load a private key of given kind from path
139 */
140 static void load_key(private_cmd_creds_t *this, key_type_t type, char *path)
141 {
142 private_key_t *privkey;
143
144 privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
145 BUILD_FROM_FILE, path, BUILD_END);
146 if (!privkey)
147 {
148 DBG1(DBG_CFG, "loading %N private key from '%s' failed",
149 key_type_names, type, path);
150 exit(1);
151 }
152 this->creds->add_key(this->creds, privkey);
153 }
154
155 /**
156 * Load a private and public key via ssh-agent
157 */
158 static void load_agent(private_cmd_creds_t *this)
159 {
160 private_key_t *privkey;
161 public_key_t *pubkey;
162 identification_t *id;
163 certificate_t *cert;
164
165 privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
166 BUILD_AGENT_SOCKET, this->agent, BUILD_END);
167 if (!privkey)
168 {
169 DBG1(DBG_CFG, "failed to load private key from ssh-agent");
170 exit(1);
171 }
172 pubkey = privkey->get_public_key(privkey);
173 if (!pubkey)
174 {
175 DBG1(DBG_CFG, "failed to load public key from ssh-agent");
176 privkey->destroy(privkey);
177 exit(1);
178 }
179 id = identification_create_from_string(this->identity);
180 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
181 CERT_TRUSTED_PUBKEY, BUILD_PUBLIC_KEY, pubkey,
182 BUILD_SUBJECT, id, BUILD_END);
183 pubkey->destroy(pubkey);
184 id->destroy(id);
185 if (!cert)
186 {
187 DBG1(DBG_CFG, "failed to create certificate for ssh-agent public key");
188 privkey->destroy(privkey);
189 exit(1);
190 }
191 this->creds->add_cert(this->creds, TRUE, cert);
192 this->creds->add_key(this->creds, privkey);
193 }
194
195 /**
196 * Load a PKCS#12 file from path
197 */
198 static void load_pkcs12(private_cmd_creds_t *this, char *path)
199 {
200 enumerator_t *enumerator;
201 certificate_t *cert;
202 private_key_t *key;
203 container_t *container;
204 pkcs12_t *pkcs12;
205
206 container = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS12,
207 BUILD_FROM_FILE, path, BUILD_END);
208 if (!container)
209 {
210 DBG1(DBG_CFG, "loading PKCS#12 file '%s' failed", path);
211 exit(1);
212 }
213 pkcs12 = (pkcs12_t*)container;
214 enumerator = pkcs12->create_cert_enumerator(pkcs12);
215 while (enumerator->enumerate(enumerator, &cert))
216 {
217 this->creds->add_cert(this->creds, TRUE, cert->get_ref(cert));
218 }
219 enumerator->destroy(enumerator);
220 enumerator = pkcs12->create_key_enumerator(pkcs12);
221 while (enumerator->enumerate(enumerator, &key))
222 {
223 this->creds->add_key(this->creds, key->get_ref(key));
224 }
225 enumerator->destroy(enumerator);
226 container->destroy(container);
227 }
228
229 METHOD(cmd_creds_t, handle, bool,
230 private_cmd_creds_t *this, cmd_option_type_t opt, char *arg)
231 {
232 switch (opt)
233 {
234 case CMD_OPT_CERT:
235 load_cert(this, arg);
236 break;
237 case CMD_OPT_RSA:
238 load_key(this, KEY_RSA, arg);
239 break;
240 case CMD_OPT_PKCS12:
241 load_pkcs12(this, arg);
242 break;
243 case CMD_OPT_IDENTITY:
244 this->identity = arg;
245 break;
246 case CMD_OPT_AGENT:
247 this->agent = arg ?: getenv("SSH_AUTH_SOCK");
248 if (!this->agent)
249 {
250 DBG1(DBG_CFG, "no ssh-agent socket defined");
251 exit(1);
252 }
253 break;
254 default:
255 return FALSE;
256 }
257 if (this->agent && this->identity)
258 {
259 load_agent(this);
260 /* only do this once */
261 this->agent = NULL;
262 }
263 return TRUE;
264 }
265
266 METHOD(cmd_creds_t, destroy, void,
267 private_cmd_creds_t *this)
268 {
269 lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
270 lib->credmgr->remove_set(lib->credmgr, &this->cb->set);
271 this->creds->destroy(this->creds);
272 this->cb->destroy(this->cb);
273 free(this);
274 }
275
276 /**
277 * See header
278 */
279 cmd_creds_t *cmd_creds_create()
280 {
281 private_cmd_creds_t *this;
282
283 INIT(this,
284 .public = {
285 .handle = _handle,
286 .destroy = _destroy,
287 },
288 .creds = mem_cred_create(),
289 .prompted = SHARED_ANY,
290 );
291 this->cb = callback_cred_create_shared((void*)callback_shared, this);
292
293 lib->credmgr->add_set(lib->credmgr, &this->creds->set);
294 lib->credmgr->add_set(lib->credmgr, &this->cb->set);
295
296 return &this->public;
297 }