a3b8eebf34e2001c1469427bde6ab357b35239e0
[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 * check if the ssh agent key blob matches to our public key
173 */
174 static bool matches_pubkey(chunk_t key, public_key_t *pubkey)
175 {
176 chunk_t pubkeydata, hash, n, e;
177 hasher_t *hasher;
178 identification_t *id;
179 bool match;
180
181 if (!pubkey)
182 {
183 return TRUE;
184 }
185 read_string(&key);
186 e = read_string(&key);
187 n = read_string(&key);
188 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
189 if (hasher == NULL)
190 {
191 return FALSE;
192 }
193 pubkeydata = asn1_wrap(ASN1_SEQUENCE, "mm",
194 asn1_wrap(ASN1_INTEGER, "c", n),
195 asn1_wrap(ASN1_INTEGER, "c", e));
196 hasher->allocate_hash(hasher, pubkeydata, &hash);
197 free(pubkeydata.ptr);
198 id = pubkey->get_id(pubkey, ID_PUBKEY_SHA1);
199 if (!id)
200 {
201 return FALSE;
202 }
203 match = chunk_equals(id->get_encoding(id), hash);
204 free(hash.ptr);
205 return match;
206 }
207
208 /**
209 * Get the first usable key from the agent
210 */
211 static bool read_key(private_agent_private_key_t *this, public_key_t *pubkey)
212 {
213 int len, count;
214 char buf[2048];
215 chunk_t blob = chunk_from_buf(buf), key, type, tmp;
216
217 len = htonl(1);
218 write(this->socket, &len, sizeof(len));
219 buf[0] = SSH_AGENT_ID_REQUEST;
220 write(this->socket, &buf, 1);
221
222 blob.len = read(this->socket, blob.ptr, blob.len);
223
224 if (blob.len < sizeof(u_int32_t) + sizeof(u_char) ||
225 read_uint32(&blob) != blob.len ||
226 read_byte(&blob) != SSH_AGENT_ID_RESPONSE)
227 {
228 DBG1("received invalid ssh-agent identity response");
229 return FALSE;
230 }
231 count = read_uint32(&blob);
232
233 while (blob.len)
234 {
235 key = read_string(&blob);
236 if (key.len)
237 {
238 tmp = key;
239 type = read_string(&tmp);
240 read_string(&tmp);
241 tmp = read_string(&tmp);
242 if (type.len && strneq("ssh-rsa", type.ptr, type.len) &&
243 tmp.len >= 512/8 && matches_pubkey(key, pubkey))
244 {
245 this->key = chunk_clone(key);
246 this->key_size = tmp.len;
247 if (tmp.ptr[0] == 0)
248 {
249 this->key_size--;
250 }
251 return TRUE;
252 }
253 continue;
254 }
255 break;
256 }
257 return FALSE;
258 }
259
260 /**
261 * Implementation of agent_private_key.destroy.
262 */
263 static bool sign(private_agent_private_key_t *this, signature_scheme_t scheme,
264 chunk_t data, chunk_t *signature)
265 {
266 u_int32_t len, flags;
267 char buf[2048];
268 chunk_t blob = chunk_from_buf(buf);
269
270 if (scheme != SIGN_DEFAULT && scheme != SIGN_RSA_EMSA_PKCS1_SHA1)
271 {
272 DBG1("signature scheme %N not supported by ssh-agent",
273 signature_scheme_names, scheme);
274 return FALSE;
275 }
276
277 len = htonl(1 + sizeof(u_int32_t) * 3 + this->key.len + data.len);
278 write(this->socket, &len, sizeof(len));
279 buf[0] = SSH_AGENT_SIGN_REQUEST;
280 write(this->socket, &buf, 1);
281
282 len = htonl(this->key.len);
283 write(this->socket, &len, sizeof(len));
284 write(this->socket, this->key.ptr, this->key.len);
285
286 len = htonl(data.len);
287 write(this->socket, &len, sizeof(len));
288 write(this->socket, data.ptr, data.len);
289
290 flags = htonl(0);
291 write(this->socket, &flags, sizeof(flags));
292
293 blob.len = read(this->socket, blob.ptr, blob.len);
294 if (blob.len < sizeof(u_int32_t) + sizeof(u_char) ||
295 read_uint32(&blob) != blob.len ||
296 read_byte(&blob) != SSH_AGENT_SIGN_RESPONSE)
297 {
298 DBG1("received invalid ssh-agent signature response");
299 return FALSE;
300 }
301 /* parse length */
302 blob = read_string(&blob);
303 /* skip sig type */
304 read_string(&blob);
305 /* parse length */
306 blob = read_string(&blob);
307 if (!blob.len)
308 {
309 DBG1("received invalid ssh-agent signature response");
310 return FALSE;
311 }
312 *signature = chunk_clone(blob);
313 return TRUE;
314 }
315
316 /**
317 * Implementation of agent_private_key.destroy.
318 */
319 static key_type_t get_type(private_agent_private_key_t *this)
320 {
321 return KEY_RSA;
322 }
323
324 /**
325 * Implementation of agent_private_key.destroy.
326 */
327 static bool decrypt(private_agent_private_key_t *this,
328 chunk_t crypto, chunk_t *plain)
329 {
330 DBG1("private key decryption not supported by ssh-agent");
331 return FALSE;
332 }
333
334 /**
335 * Implementation of agent_private_key.destroy.
336 */
337 static size_t get_keysize(private_agent_private_key_t *this)
338 {
339 return this->key_size;
340 }
341
342 /**
343 * Implementation of agent_private_key.destroy.
344 */
345 static identification_t* get_id(private_agent_private_key_t *this,
346 id_type_t type)
347 {
348 switch (type)
349 {
350 case ID_PUBKEY_INFO_SHA1:
351 return this->keyid_info;
352 case ID_PUBKEY_SHA1:
353 return this->keyid;
354 default:
355 return NULL;
356 }
357 }
358
359 /**
360 * Implementation of agent_private_key.get_public_key.
361 */
362 static public_key_t* get_public_key(private_agent_private_key_t *this)
363 {
364 chunk_t key, n, e, encoded;
365 public_key_t *public;
366
367 key = this->key;
368 read_string(&key);
369 e = read_string(&key);
370 n = read_string(&key);
371 encoded = asn1_wrap(ASN1_SEQUENCE, "mm",
372 asn1_wrap(ASN1_INTEGER, "c", n),
373 asn1_wrap(ASN1_INTEGER, "c", e));
374
375 public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
376 BUILD_BLOB_ASN1_DER, encoded, BUILD_END);
377 free(encoded.ptr);
378 return public;
379 }
380
381 /**
382 * Implementation of agent_private_key.belongs_to.
383 */
384 static bool belongs_to(private_agent_private_key_t *this, public_key_t *public)
385 {
386 identification_t *keyid;
387
388 if (public->get_type(public) != KEY_RSA)
389 {
390 return FALSE;
391 }
392 keyid = public->get_id(public, ID_PUBKEY_SHA1);
393 if (keyid && keyid->equals(keyid, this->keyid))
394 {
395 return TRUE;
396 }
397 keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1);
398 if (keyid && keyid->equals(keyid, this->keyid_info))
399 {
400 return TRUE;
401 }
402 return FALSE;
403 }
404
405 /**
406 * Build the RSA key identifier from n and e using SHA1 hashed publicKey(Info).
407 */
408 static bool build_ids(private_agent_private_key_t *this)
409 {
410 chunk_t publicKeyInfo, publicKey, hash, key, n, e;
411 hasher_t *hasher;
412
413 key = this->key;
414 read_string(&key);
415 e = read_string(&key);
416 n = read_string(&key);
417
418 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
419 if (hasher == NULL)
420 {
421 DBG1("SHA1 hash algorithm not supported, unable to use RSA");
422 return FALSE;
423 }
424 publicKey = asn1_wrap(ASN1_SEQUENCE, "mm",
425 asn1_wrap(ASN1_INTEGER, "c", n),
426 asn1_wrap(ASN1_INTEGER, "c", e));
427 hasher->allocate_hash(hasher, publicKey, &hash);
428 this->keyid = identification_create_from_encoding(ID_PUBKEY_SHA1, hash);
429 chunk_free(&hash);
430
431 publicKeyInfo = asn1_wrap(ASN1_SEQUENCE, "cm",
432 asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
433 asn1_bitstring("m", publicKey));
434 hasher->allocate_hash(hasher, publicKeyInfo, &hash);
435 this->keyid_info = identification_create_from_encoding(ID_PUBKEY_INFO_SHA1, hash);
436 chunk_free(&hash);
437
438 hasher->destroy(hasher);
439 chunk_free(&publicKeyInfo);
440 return TRUE;
441 }
442
443 /**
444 * Implementation of private_key_t.get_encoding.
445 */
446 static chunk_t get_encoding(private_agent_private_key_t *this)
447 {
448 return chunk_empty;
449 }
450
451 /**
452 * Implementation of agent_private_key.get_ref.
453 */
454 static private_agent_private_key_t* get_ref(private_agent_private_key_t *this)
455 {
456 ref_get(&this->ref);
457 return this;
458 }
459
460 /**
461 * Implementation of agent_private_key.destroy.
462 */
463 static void destroy(private_agent_private_key_t *this)
464 {
465 if (ref_put(&this->ref))
466 {
467 close(this->socket);
468 DESTROY_IF(this->keyid);
469 DESTROY_IF(this->keyid_info);
470 free(this->key.ptr);
471 free(this);
472 }
473 }
474
475 /**
476 * Internal constructor
477 */
478 static agent_private_key_t *agent_private_key_create(char *path,
479 public_key_t *pubkey)
480 {
481 private_agent_private_key_t *this = malloc_thing(private_agent_private_key_t);
482
483 this->public.interface.get_type = (key_type_t (*)(private_key_t *this))get_type;
484 this->public.interface.sign = (bool (*)(private_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t *signature))sign;
485 this->public.interface.decrypt = (bool (*)(private_key_t *this, chunk_t crypto, chunk_t *plain))decrypt;
486 this->public.interface.get_keysize = (size_t (*) (private_key_t *this))get_keysize;
487 this->public.interface.get_id = (identification_t* (*) (private_key_t *this,id_type_t))get_id;
488 this->public.interface.get_public_key = (public_key_t* (*)(private_key_t *this))get_public_key;
489 this->public.interface.belongs_to = (bool (*) (private_key_t *this, public_key_t *public))belongs_to;
490 this->public.interface.get_encoding = (chunk_t(*)(private_key_t*))get_encoding;
491 this->public.interface.get_ref = (private_key_t* (*)(private_key_t *this))get_ref;
492 this->public.interface.destroy = (void (*)(private_key_t *this))destroy;
493
494 this->socket = open_connection(path);
495 if (this->socket < 0)
496 {
497 free(this);
498 return NULL;
499 }
500 this->key = chunk_empty;
501 this->keyid = NULL;
502 this->keyid_info = NULL;
503 this->ref = 1;
504 if (!read_key(this, pubkey) || !build_ids(this))
505 {
506 destroy(this);
507 return NULL;
508 }
509 return &this->public;
510 }
511
512 typedef struct private_builder_t private_builder_t;
513 /**
514 * Builder implementation for key loading/generation
515 */
516 struct private_builder_t {
517 /** implements the builder interface */
518 builder_t public;
519 /** agent unix socket */
520 char *socket;
521 /** matching public key */
522 public_key_t *pubkey;
523 };
524
525 /**
526 * Implementation of builder_t.build
527 */
528 static agent_private_key_t *build(private_builder_t *this)
529 {
530 agent_private_key_t *key = NULL;
531
532 if (this->socket)
533 {
534 key = agent_private_key_create(this->socket, this->pubkey);
535 }
536 free(this);
537 return key;
538 }
539
540 /**
541 * Implementation of builder_t.add
542 */
543 static void add(private_builder_t *this, builder_part_t part, ...)
544 {
545 va_list args;
546
547 switch (part)
548 {
549 case BUILD_AGENT_SOCKET:
550 {
551 va_start(args, part);
552 this->socket = va_arg(args, char*);
553 va_end(args);
554 return;
555 }
556 case BUILD_PUBLIC_KEY:
557 {
558 va_start(args, part);
559 this->pubkey = va_arg(args, public_key_t*);
560 va_end(args);
561 return;
562 }
563 default:
564 break;
565 }
566 builder_cancel(&this->public);
567 }
568
569 /**
570 * Builder construction function
571 */
572 builder_t *agent_private_key_builder(key_type_t type)
573 {
574 private_builder_t *this;
575
576 if (type != KEY_RSA)
577 {
578 return NULL;
579 }
580
581 this = malloc_thing(private_builder_t);
582
583 this->pubkey = NULL;
584 this->socket = NULL;
585 this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add;
586 this->public.build = (void*(*)(builder_t *this))build;
587
588 return &this->public;
589 }
590