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