7fee85d789995750bc77203cbe366cbe769291a0
[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/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;
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 pwd = getpass(label);
99 if (!pwd || strlen(pwd) == 0)
100 {
101 return NULL;
102 }
103 this->prompted = type;
104 if (match_me)
105 {
106 *match_me = ID_MATCH_PERFECT;
107 }
108 if (match_other)
109 {
110 *match_other = ID_MATCH_PERFECT;
111 }
112 shared = shared_key_create(type, chunk_clone(chunk_from_str(pwd)));
113 /* cache password in case it is required more than once */
114 this->creds->add_shared(this->creds, shared, NULL);
115 return shared->get_ref(shared);
116 }
117
118 /**
119 * Load a trusted certificate from path
120 */
121 static void load_cert(private_cmd_creds_t *this, char *path)
122 {
123 certificate_t *cert;
124
125 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
126 BUILD_FROM_FILE, path, BUILD_END);
127 if (!cert)
128 {
129 DBG1(DBG_CFG, "loading certificate from '%s' failed", path);
130 exit(1);
131 }
132 this->creds->add_cert(this->creds, TRUE, cert);
133 }
134
135 /**
136 * Load a private key of given kind from path
137 */
138 static void load_key(private_cmd_creds_t *this, key_type_t type, char *path)
139 {
140 private_key_t *privkey;
141
142 privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
143 BUILD_FROM_FILE, path, BUILD_END);
144 if (!privkey)
145 {
146 DBG1(DBG_CFG, "loading %N private key from '%s' failed",
147 key_type_names, type, path);
148 exit(1);
149 }
150 this->creds->add_key(this->creds, privkey);
151 }
152
153 /**
154 * Load a private and public key via ssh-agent
155 */
156 static void load_agent(private_cmd_creds_t *this)
157 {
158 private_key_t *privkey;
159 public_key_t *pubkey;
160 identification_t *id;
161 certificate_t *cert;
162
163 privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
164 BUILD_AGENT_SOCKET, this->agent, BUILD_END);
165 if (!privkey)
166 {
167 DBG1(DBG_CFG, "failed to load private key from ssh-agent");
168 exit(1);
169 }
170 pubkey = privkey->get_public_key(privkey);
171 if (!pubkey)
172 {
173 DBG1(DBG_CFG, "failed to load public key from ssh-agent");
174 privkey->destroy(privkey);
175 exit(1);
176 }
177 id = identification_create_from_string(this->identity);
178 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
179 CERT_TRUSTED_PUBKEY, BUILD_PUBLIC_KEY, pubkey,
180 BUILD_SUBJECT, id, BUILD_END);
181 pubkey->destroy(pubkey);
182 id->destroy(id);
183 if (!cert)
184 {
185 DBG1(DBG_CFG, "failed to create certificate for ssh-agent public key");
186 privkey->destroy(privkey);
187 exit(1);
188 }
189 this->creds->add_cert(this->creds, TRUE, cert);
190 this->creds->add_key(this->creds, privkey);
191 }
192
193 /**
194 * Load a PKCS#12 file from path
195 */
196 static void load_pkcs12(private_cmd_creds_t *this, char *path)
197 {
198 enumerator_t *enumerator;
199 certificate_t *cert;
200 private_key_t *key;
201 container_t *container;
202 pkcs12_t *pkcs12;
203
204 container = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS12,
205 BUILD_FROM_FILE, path, BUILD_END);
206 if (!container)
207 {
208 DBG1(DBG_CFG, "loading PKCS#12 file '%s' failed", path);
209 exit(1);
210 }
211 pkcs12 = (pkcs12_t*)container;
212 enumerator = pkcs12->create_cert_enumerator(pkcs12);
213 while (enumerator->enumerate(enumerator, &cert))
214 {
215 this->creds->add_cert(this->creds, TRUE, cert->get_ref(cert));
216 }
217 enumerator->destroy(enumerator);
218 enumerator = pkcs12->create_key_enumerator(pkcs12);
219 while (enumerator->enumerate(enumerator, &key))
220 {
221 this->creds->add_key(this->creds, key->get_ref(key));
222 }
223 enumerator->destroy(enumerator);
224 container->destroy(container);
225 }
226
227 METHOD(cmd_creds_t, handle, bool,
228 private_cmd_creds_t *this, cmd_option_type_t opt, char *arg)
229 {
230 switch (opt)
231 {
232 case CMD_OPT_CERT:
233 load_cert(this, arg);
234 break;
235 case CMD_OPT_RSA:
236 load_key(this, KEY_RSA, arg);
237 break;
238 case CMD_OPT_PKCS12:
239 load_pkcs12(this, arg);
240 break;
241 case CMD_OPT_IDENTITY:
242 this->identity = arg;
243 break;
244 case CMD_OPT_AGENT:
245 this->agent = arg ?: getenv("SSH_AUTH_SOCK");
246 if (!this->agent)
247 {
248 DBG1(DBG_CFG, "no ssh-agent socket defined");
249 exit(1);
250 }
251 break;
252 default:
253 return FALSE;
254 }
255 if (this->agent && this->identity)
256 {
257 load_agent(this);
258 /* only do this once */
259 this->agent = NULL;
260 }
261 return TRUE;
262 }
263
264 METHOD(cmd_creds_t, destroy, void,
265 private_cmd_creds_t *this)
266 {
267 lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
268 lib->credmgr->remove_set(lib->credmgr, &this->cb->set);
269 this->creds->destroy(this->creds);
270 this->cb->destroy(this->cb);
271 free(this);
272 }
273
274 /**
275 * See header
276 */
277 cmd_creds_t *cmd_creds_create()
278 {
279 private_cmd_creds_t *this;
280
281 INIT(this,
282 .public = {
283 .handle = _handle,
284 .destroy = _destroy,
285 },
286 .creds = mem_cred_create(),
287 .prompted = SHARED_ANY,
288 );
289 this->cb = callback_cred_create_shared((void*)callback_shared, this);
290
291 lib->credmgr->add_set(lib->credmgr, &this->creds->set);
292 lib->credmgr->add_set(lib->credmgr, &this->cb->set);
293
294 return &this->public;
295 }