libstrongswan agent plugin to use ssh-agent for RSA signatures
[strongswan.git] / src / libstrongswan / plugins / agent / agent_private_key.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
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>.
9 *
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
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #include "agent_private_key.h"
19
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <sys/un.h>
25 #include <arpa/inet.h>
26 #include <errno.h>
27
28 #include <library.h>
29 #include <chunk.h>
30 #include <debug.h>
31 #include <asn1/asn1.h>
32 #include <asn1/oid.h>
33
34 #ifndef UNIX_PATH_MAX
35 #define UNIX_PATH_MAX 108
36 #endif /* UNIX_PATH_MAX */
37
38 typedef struct private_agent_private_key_t private_agent_private_key_t;
39 typedef enum agent_msg_type_t agent_msg_type_t;
40
41 /**
42 * Private data of a agent_private_key_t object.
43 */
44 struct private_agent_private_key_t {
45 /**
46 * Public interface for this signer.
47 */
48 agent_private_key_t public;
49
50 /**
51 * ssh-agent unix socket connection
52 */
53 int socket;
54
55 /**
56 * key identity blob in ssh format
57 */
58 chunk_t key;
59
60 /**
61 * keysize in bytes
62 */
63 size_t key_size;
64
65 /**
66 * Keyid formed as a SHA-1 hash of a publicKey object
67 */
68 identification_t* keyid;
69
70 /**
71 * Keyid formed as a SHA-1 hash of a publicKeyInfo object
72 */
73 identification_t* keyid_info;
74
75 /**
76 * reference count
77 */
78 refcount_t ref;
79 };
80
81 /**
82 * Message types for ssh-agent protocol
83 */
84 enum agent_msg_type_t {
85 SSH_AGENT_FAILURE = 5,
86 SSH_AGENT_SUCCESS = 6,
87 SSH_AGENT_ID_REQUEST = 11,
88 SSH_AGENT_ID_RESPONSE = 12,
89 SSH_AGENT_SIGN_REQUEST = 13,
90 SSH_AGENT_SIGN_RESPONSE = 14,
91 };
92
93 /**
94 * read a byte from a blob
95 */
96 static u_char read_byte(chunk_t *blob)
97 {
98 u_char val;
99
100 if (blob->len < sizeof(u_char))
101 {
102 return 0;
103 }
104 val = *(blob->ptr);
105 *blob = chunk_skip(*blob, sizeof(u_char));
106 return val;
107 }
108
109 /**
110 * read a u_int32_t from a blob
111 */
112 static u_int32_t read_uint32(chunk_t *blob)
113 {
114 u_int32_t val;
115
116 if (blob->len < sizeof(u_int32_t))
117 {
118 return 0;
119 }
120 val = ntohl(*(u_int32_t*)blob->ptr);
121 *blob = chunk_skip(*blob, sizeof(u_int32_t));
122 return val;
123 }
124
125 /**
126 * read a ssh-agent "string" length/value from a blob
127 */
128 static chunk_t read_string(chunk_t *blob)
129 {
130 int len;
131 chunk_t str;
132
133 len = read_uint32(blob);
134 if (len > blob->len)
135 {
136 return chunk_empty;
137 }
138 str = chunk_create(blob->ptr, len);
139 *blob = chunk_skip(*blob, + len);
140 return str;
141 }
142
143 /**
144 * open socket connection to the ssh-agent
145 */
146 static int open_connection(char *path)
147 {
148 struct sockaddr_un addr;
149 int s;
150
151 s = socket(AF_UNIX, SOCK_STREAM, 0);
152 if (s == -1)
153 {
154 DBG1("opening ssh-agent socket %s failed: %s:", path, strerror(errno));
155 return -1;
156 }
157
158 addr.sun_family = AF_UNIX;
159 addr.sun_path[UNIX_PATH_MAX - 1] = '\0';
160 strncpy(addr.sun_path, path, UNIX_PATH_MAX - 1);
161
162 if (connect(s, (struct sockaddr*)&addr, SUN_LEN(&addr)) != 0)
163 {
164 DBG1("connecting to ssh-agent socket failed: %s", strerror(errno));
165 close(s);
166 return -1;
167 }
168 return s;
169 }
170
171 /**
172 * Get the first usable key from the agent
173 */
174 static bool read_key(private_agent_private_key_t *this)
175 {
176 int len, count;
177 char buf[2048];
178 chunk_t blob = chunk_from_buf(buf), key, type, tmp;
179
180 len = htonl(1);
181 write(this->socket, &len, sizeof(len));
182 buf[0] = SSH_AGENT_ID_REQUEST;
183 write(this->socket, &buf, 1);
184
185 blob.len = read(this->socket, blob.ptr, blob.len);
186
187 if (blob.len < sizeof(u_int32_t) + sizeof(u_char) ||
188 read_uint32(&blob) != blob.len ||
189 read_byte(&blob) != SSH_AGENT_ID_RESPONSE)
190 {
191 DBG1("received invalid ssh-agent identity response");
192 return FALSE;
193 }
194 count = read_uint32(&blob);
195
196 while (blob.len)
197 {
198 key = read_string(&blob);
199 if (key.len)
200 {
201 tmp = key;
202 type = read_string(&tmp);
203 read_string(&tmp);
204 tmp = read_string(&tmp);
205 if (type.len && strneq("ssh-rsa", type.ptr, type.len) &&
206 tmp.len >= 512/8)
207 {
208 this->key = chunk_clone(key);
209 this->key_size = tmp.len;
210 if (tmp.ptr[0] == 0)
211 {
212 this->key_size--;
213 }
214 return TRUE;
215 }
216 continue;
217 }
218 break;
219 }
220 return FALSE;
221 }
222
223 /**
224 * Implementation of agent_private_key.destroy.
225 */
226 static bool sign(private_agent_private_key_t *this, signature_scheme_t scheme,
227 chunk_t data, chunk_t *signature)
228 {
229 u_int32_t len, flags;
230 char buf[2048];
231 chunk_t blob = chunk_from_buf(buf);
232
233 if (scheme != SIGN_DEFAULT && scheme != SIGN_RSA_EMSA_PKCS1_SHA1)
234 {
235 DBG1("signature scheme %N not supported by ssh-agent",
236 signature_scheme_names, scheme);
237 return FALSE;
238 }
239
240 len = htonl(1 + sizeof(u_int32_t) * 3 + this->key.len + data.len);
241 write(this->socket, &len, sizeof(len));
242 buf[0] = SSH_AGENT_SIGN_REQUEST;
243 write(this->socket, &buf, 1);
244
245 len = htonl(this->key.len);
246 write(this->socket, &len, sizeof(len));
247 write(this->socket, this->key.ptr, this->key.len);
248
249 len = htonl(data.len);
250 write(this->socket, &len, sizeof(len));
251 write(this->socket, data.ptr, data.len);
252
253 flags = htonl(0);
254 write(this->socket, &flags, sizeof(flags));
255
256 blob.len = read(this->socket, blob.ptr, blob.len);
257 if (blob.len < sizeof(u_int32_t) + sizeof(u_char) ||
258 read_uint32(&blob) != blob.len ||
259 read_byte(&blob) != SSH_AGENT_SIGN_RESPONSE)
260 {
261 DBG1("received invalid ssh-agent signature response");
262 return FALSE;
263 }
264 /* parse length */
265 blob = read_string(&blob);
266 /* skip sig type */
267 read_string(&blob);
268 /* parse length */
269 blob = read_string(&blob);
270 if (!blob.len)
271 {
272 DBG1("received invalid ssh-agent signature response");
273 return FALSE;
274 }
275 *signature = chunk_clone(blob);
276 return TRUE;
277 }
278
279 /**
280 * Implementation of agent_private_key.destroy.
281 */
282 static key_type_t get_type(private_agent_private_key_t *this)
283 {
284 return KEY_RSA;
285 }
286
287 /**
288 * Implementation of agent_private_key.destroy.
289 */
290 static bool decrypt(private_agent_private_key_t *this,
291 chunk_t crypto, chunk_t *plain)
292 {
293 DBG1("private key decryption not supported by ssh-agent");
294 return FALSE;
295 }
296
297 /**
298 * Implementation of agent_private_key.destroy.
299 */
300 static size_t get_keysize(private_agent_private_key_t *this)
301 {
302 return this->key_size;
303 }
304
305 /**
306 * Implementation of agent_private_key.destroy.
307 */
308 static identification_t* get_id(private_agent_private_key_t *this,
309 id_type_t type)
310 {
311 switch (type)
312 {
313 case ID_PUBKEY_INFO_SHA1:
314 return this->keyid_info;
315 case ID_PUBKEY_SHA1:
316 return this->keyid;
317 default:
318 return NULL;
319 }
320 }
321
322 /**
323 * Implementation of agent_private_key.get_public_key.
324 */
325 static public_key_t* get_public_key(private_agent_private_key_t *this)
326 {
327 chunk_t key, n, e, encoded;
328 public_key_t *public;
329
330 key = this->key;
331 read_string(&key);
332 e = read_string(&key);
333 n = read_string(&key);
334 encoded = asn1_wrap(ASN1_SEQUENCE, "mm",
335 asn1_wrap(ASN1_INTEGER, "c", n),
336 asn1_wrap(ASN1_INTEGER, "c", e));
337
338 public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
339 BUILD_BLOB_ASN1_DER, encoded, BUILD_END);
340 free(encoded.ptr);
341 return public;
342 }
343
344 /**
345 * Implementation of agent_private_key.belongs_to.
346 */
347 static bool belongs_to(private_agent_private_key_t *this, public_key_t *public)
348 {
349 identification_t *keyid;
350
351 if (public->get_type(public) != KEY_RSA)
352 {
353 return FALSE;
354 }
355 keyid = public->get_id(public, ID_PUBKEY_SHA1);
356 if (keyid && keyid->equals(keyid, this->keyid))
357 {
358 return TRUE;
359 }
360 keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1);
361 if (keyid && keyid->equals(keyid, this->keyid_info))
362 {
363 return TRUE;
364 }
365 return FALSE;
366 }
367
368 /**
369 * Build the RSA key identifier from n and e using SHA1 hashed publicKey(Info).
370 */
371 static bool build_ids(private_agent_private_key_t *this)
372 {
373 chunk_t publicKeyInfo, publicKey, hash, key, n, e;
374 hasher_t *hasher;
375
376 key = this->key;
377 e = read_string(&key);
378 n = read_string(&key);
379
380 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
381 if (hasher == NULL)
382 {
383 DBG1("SHA1 hash algorithm not supported, unable to use RSA");
384 return FALSE;
385 }
386 publicKey = asn1_wrap(ASN1_SEQUENCE, "cc", n, e);
387 hasher->allocate_hash(hasher, publicKey, &hash);
388 this->keyid = identification_create_from_encoding(ID_PUBKEY_SHA1, hash);
389 chunk_free(&hash);
390
391 publicKeyInfo = asn1_wrap(ASN1_SEQUENCE, "cm",
392 asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
393 asn1_bitstring("m", publicKey));
394 hasher->allocate_hash(hasher, publicKeyInfo, &hash);
395 this->keyid_info = identification_create_from_encoding(ID_PUBKEY_INFO_SHA1, hash);
396 chunk_free(&hash);
397
398 hasher->destroy(hasher);
399 chunk_free(&publicKeyInfo);
400 return TRUE;
401 }
402
403 /**
404 * Implementation of private_key_t.get_encoding.
405 */
406 static chunk_t get_encoding(private_agent_private_key_t *this)
407 {
408 return chunk_empty;
409 }
410
411 /**
412 * Implementation of agent_private_key.get_ref.
413 */
414 static private_agent_private_key_t* get_ref(private_agent_private_key_t *this)
415 {
416 ref_get(&this->ref);
417 return this;
418 }
419
420 /**
421 * Implementation of agent_private_key.destroy.
422 */
423 static void destroy(private_agent_private_key_t *this)
424 {
425 if (ref_put(&this->ref))
426 {
427 close(this->socket);
428 DESTROY_IF(this->keyid);
429 DESTROY_IF(this->keyid_info);
430 free(this->key.ptr);
431 free(this);
432 }
433 }
434
435 /**
436 * Internal constructor
437 */
438 static agent_private_key_t *agent_private_key_create(char *path)
439 {
440 private_agent_private_key_t *this = malloc_thing(private_agent_private_key_t);
441
442 this->public.interface.get_type = (key_type_t (*)(private_key_t *this))get_type;
443 this->public.interface.sign = (bool (*)(private_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t *signature))sign;
444 this->public.interface.decrypt = (bool (*)(private_key_t *this, chunk_t crypto, chunk_t *plain))decrypt;
445 this->public.interface.get_keysize = (size_t (*) (private_key_t *this))get_keysize;
446 this->public.interface.get_id = (identification_t* (*) (private_key_t *this,id_type_t))get_id;
447 this->public.interface.get_public_key = (public_key_t* (*)(private_key_t *this))get_public_key;
448 this->public.interface.belongs_to = (bool (*) (private_key_t *this, public_key_t *public))belongs_to;
449 this->public.interface.get_encoding = (chunk_t(*)(private_key_t*))get_encoding;
450 this->public.interface.get_ref = (private_key_t* (*)(private_key_t *this))get_ref;
451 this->public.interface.destroy = (void (*)(private_key_t *this))destroy;
452
453 this->socket = open_connection(path);
454 if (this->socket < 0)
455 {
456 free(this);
457 return NULL;
458 }
459 this->keyid = NULL;
460 this->keyid_info = NULL;
461 this->ref = 1;
462 if (!read_key(this) || !build_ids(this))
463 {
464 destroy(this);
465 return NULL;
466 }
467 return &this->public;
468 }
469
470 typedef struct private_builder_t private_builder_t;
471 /**
472 * Builder implementation for key loading/generation
473 */
474 struct private_builder_t {
475 /** implements the builder interface */
476 builder_t public;
477 /** loaded/generated private key */
478 agent_private_key_t *key;
479 };
480
481 /**
482 * Implementation of builder_t.build
483 */
484 static agent_private_key_t *build(private_builder_t *this)
485 {
486 agent_private_key_t *key = this->key;
487
488 free(this);
489 return key;
490 }
491
492 /**
493 * Implementation of builder_t.add
494 */
495 static void add(private_builder_t *this, builder_part_t part, ...)
496 {
497 va_list args;
498
499 if (this->key)
500 {
501 DBG1("ignoring surplus build part %N", builder_part_names, part);
502 return;
503 }
504
505 switch (part)
506 {
507 case BUILD_AGENT_SOCKET:
508 {
509 va_start(args, part);
510 this->key = agent_private_key_create(va_arg(args, char*));
511 va_end(args);
512 break;
513 }
514 default:
515 DBG1("ignoring unsupported build part %N", builder_part_names, part);
516 break;
517 }
518 }
519
520 /**
521 * Builder construction function
522 */
523 builder_t *agent_private_key_builder(key_type_t type)
524 {
525 private_builder_t *this;
526
527 if (type != KEY_RSA)
528 {
529 return NULL;
530 }
531
532 this = malloc_thing(private_builder_t);
533
534 this->key = NULL;
535 this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add;
536 this->public.build = (void*(*)(builder_t *this))build;
537
538 return &this->public;
539 }
540