Line data Source code
1 : /* command-ssh.c - gpg-agent's ssh-agent emulation layer
2 : * Copyright (C) 2004-2006, 2009, 2012 Free Software Foundation, Inc.
3 : * Copyright (C) 2004-2006, 2009, 2012-2014 Werner Koch
4 : *
5 : * This file is part of GnuPG.
6 : *
7 : * GnuPG is free software; you can redistribute it and/or modify
8 : * it under the terms of the GNU General Public License as published by
9 : * the Free Software Foundation; either version 3 of the License, or
10 : * (at your option) any later version.
11 : *
12 : * GnuPG is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : * GNU General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU General Public License
18 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : /* Only v2 of the ssh-agent protocol is implemented. Relevant RFCs
22 : are:
23 :
24 : RFC-4250 - Protocol Assigned Numbers
25 : RFC-4251 - Protocol Architecture
26 : RFC-4252 - Authentication Protocol
27 : RFC-4253 - Transport Layer Protocol
28 : RFC-5656 - ECC support
29 :
30 : The protocol for the agent is defined in OpenSSH's PROTOCL.agent
31 : file.
32 : */
33 :
34 : #include <config.h>
35 :
36 : #include <stdio.h>
37 : #include <stdlib.h>
38 : #include <string.h>
39 : #include <errno.h>
40 : #include <sys/types.h>
41 : #include <sys/stat.h>
42 : #include <assert.h>
43 :
44 : #include "agent.h"
45 :
46 : #include "i18n.h"
47 : #include "../common/ssh-utils.h"
48 :
49 :
50 :
51 :
52 : /* Request types. */
53 : #define SSH_REQUEST_REQUEST_IDENTITIES 11
54 : #define SSH_REQUEST_SIGN_REQUEST 13
55 : #define SSH_REQUEST_ADD_IDENTITY 17
56 : #define SSH_REQUEST_REMOVE_IDENTITY 18
57 : #define SSH_REQUEST_REMOVE_ALL_IDENTITIES 19
58 : #define SSH_REQUEST_LOCK 22
59 : #define SSH_REQUEST_UNLOCK 23
60 : #define SSH_REQUEST_ADD_ID_CONSTRAINED 25
61 :
62 : /* Options. */
63 : #define SSH_OPT_CONSTRAIN_LIFETIME 1
64 : #define SSH_OPT_CONSTRAIN_CONFIRM 2
65 :
66 : /* Response types. */
67 : #define SSH_RESPONSE_SUCCESS 6
68 : #define SSH_RESPONSE_FAILURE 5
69 : #define SSH_RESPONSE_IDENTITIES_ANSWER 12
70 : #define SSH_RESPONSE_SIGN_RESPONSE 14
71 :
72 : /* Other constants. */
73 : #define SSH_DSA_SIGNATURE_PADDING 20
74 : #define SSH_DSA_SIGNATURE_ELEMS 2
75 : #define SPEC_FLAG_USE_PKCS1V2 (1 << 0)
76 : #define SPEC_FLAG_IS_ECDSA (1 << 1)
77 : #define SPEC_FLAG_IS_EdDSA (1 << 2) /*(lowercase 'd' on purpose.)*/
78 :
79 : /* The name of the control file. */
80 : #define SSH_CONTROL_FILE_NAME "sshcontrol"
81 :
82 : /* The blurb we put into the header of a newly created control file. */
83 : static const char sshcontrolblurb[] =
84 : "# List of allowed ssh keys. Only keys present in this file are used\n"
85 : "# in the SSH protocol. The ssh-add tool may add new entries to this\n"
86 : "# file to enable them; you may also add them manually. Comment\n"
87 : "# lines, like this one, as well as empty lines are ignored. Lines do\n"
88 : "# have a certain length limit but this is not serious limitation as\n"
89 : "# the format of the entries is fixed and checked by gpg-agent. A\n"
90 : "# non-comment line starts with optional white spaces, followed by the\n"
91 : "# keygrip of the key given as 40 hex digits, optionally followed by a\n"
92 : "# caching TTL in seconds, and another optional field for arbitrary\n"
93 : "# flags. Prepend the keygrip with an '!' mark to disable it.\n"
94 : "\n";
95 :
96 :
97 : /* Macros. */
98 :
99 : /* Return a new uint32 with b0 being the most significant byte and b3
100 : being the least significant byte. */
101 : #define uint32_construct(b0, b1, b2, b3) \
102 : ((b0 << 24) | (b1 << 16) | (b2 << 8) | b3)
103 :
104 :
105 :
106 :
107 : /*
108 : * Basic types.
109 : */
110 :
111 : /* Type for a request handler. */
112 : typedef gpg_error_t (*ssh_request_handler_t) (ctrl_t ctrl,
113 : estream_t request,
114 : estream_t response);
115 :
116 :
117 : struct ssh_key_type_spec;
118 : typedef struct ssh_key_type_spec ssh_key_type_spec_t;
119 :
120 : /* Type, which is used for associating request handlers with the
121 : appropriate request IDs. */
122 : typedef struct ssh_request_spec
123 : {
124 : unsigned char type;
125 : ssh_request_handler_t handler;
126 : const char *identifier;
127 : unsigned int secret_input;
128 : } ssh_request_spec_t;
129 :
130 : /* Type for "key modifier functions", which are necessary since
131 : OpenSSH and GnuPG treat key material slightly different. A key
132 : modifier is called right after a new key identity has been received
133 : in order to "sanitize" the material. */
134 : typedef gpg_error_t (*ssh_key_modifier_t) (const char *elems,
135 : gcry_mpi_t *mpis);
136 :
137 : /* The encoding of a generated signature is dependent on the
138 : algorithm; therefore algorithm specific signature encoding
139 : functions are necessary. */
140 : typedef gpg_error_t (*ssh_signature_encoder_t) (ssh_key_type_spec_t *spec,
141 : estream_t signature_blob,
142 : gcry_sexp_t sig);
143 :
144 : /* Type, which is used for boundling all the algorithm specific
145 : information together in a single object. */
146 : struct ssh_key_type_spec
147 : {
148 : /* Algorithm identifier as used by OpenSSH. */
149 : const char *ssh_identifier;
150 :
151 : /* Human readable name of the algorithm. */
152 : const char *name;
153 :
154 : /* Algorithm identifier as used by GnuPG. */
155 : const char *identifier;
156 :
157 : /* List of MPI names for secret keys; order matches the one of the
158 : agent protocol. */
159 : const char *elems_key_secret;
160 :
161 : /* List of MPI names for public keys; order matches the one of the
162 : agent protocol. */
163 : const char *elems_key_public;
164 :
165 : /* List of MPI names for signature data. */
166 : const char *elems_signature;
167 :
168 : /* List of MPI names for secret keys; order matches the one, which
169 : is required by gpg-agent's key access layer. */
170 : const char *elems_sexp_order;
171 :
172 : /* Key modifier function. Key modifier functions are necessary in
173 : order to fix any inconsistencies between the representation of
174 : keys on the SSH and on the GnuPG side. */
175 : ssh_key_modifier_t key_modifier;
176 :
177 : /* Signature encoder function. Signature encoder functions are
178 : necessary since the encoding of signatures depends on the used
179 : algorithm. */
180 : ssh_signature_encoder_t signature_encoder;
181 :
182 : /* The name of the ECC curve or NULL. */
183 : const char *curve_name;
184 :
185 : /* The hash algorithm to be used with this key. 0 for using the
186 : default. */
187 : int hash_algo;
188 :
189 : /* Misc flags. */
190 : unsigned int flags;
191 : };
192 :
193 :
194 : /* Definition of an object to access the sshcontrol file. */
195 : struct ssh_control_file_s
196 : {
197 : char *fname; /* Name of the file. */
198 : FILE *fp; /* This is never NULL. */
199 : int lnr; /* The current line number. */
200 : struct {
201 : int valid; /* True if the data of this structure is valid. */
202 : int disabled; /* The item is disabled. */
203 : int ttl; /* The TTL of the item. */
204 : int confirm; /* The confirm flag is set. */
205 : char hexgrip[40+1]; /* The hexgrip of the item (uppercase). */
206 : } item;
207 : };
208 :
209 :
210 : /* Prototypes. */
211 : static gpg_error_t ssh_handler_request_identities (ctrl_t ctrl,
212 : estream_t request,
213 : estream_t response);
214 : static gpg_error_t ssh_handler_sign_request (ctrl_t ctrl,
215 : estream_t request,
216 : estream_t response);
217 : static gpg_error_t ssh_handler_add_identity (ctrl_t ctrl,
218 : estream_t request,
219 : estream_t response);
220 : static gpg_error_t ssh_handler_remove_identity (ctrl_t ctrl,
221 : estream_t request,
222 : estream_t response);
223 : static gpg_error_t ssh_handler_remove_all_identities (ctrl_t ctrl,
224 : estream_t request,
225 : estream_t response);
226 : static gpg_error_t ssh_handler_lock (ctrl_t ctrl,
227 : estream_t request,
228 : estream_t response);
229 : static gpg_error_t ssh_handler_unlock (ctrl_t ctrl,
230 : estream_t request,
231 : estream_t response);
232 :
233 : static gpg_error_t ssh_key_modifier_rsa (const char *elems, gcry_mpi_t *mpis);
234 : static gpg_error_t ssh_signature_encoder_rsa (ssh_key_type_spec_t *spec,
235 : estream_t signature_blob,
236 : gcry_sexp_t signature);
237 : static gpg_error_t ssh_signature_encoder_dsa (ssh_key_type_spec_t *spec,
238 : estream_t signature_blob,
239 : gcry_sexp_t signature);
240 : static gpg_error_t ssh_signature_encoder_ecdsa (ssh_key_type_spec_t *spec,
241 : estream_t signature_blob,
242 : gcry_sexp_t signature);
243 : static gpg_error_t ssh_signature_encoder_eddsa (ssh_key_type_spec_t *spec,
244 : estream_t signature_blob,
245 : gcry_sexp_t signature);
246 : static gpg_error_t ssh_key_extract_comment (gcry_sexp_t key, char **comment);
247 :
248 :
249 :
250 : /* Global variables. */
251 :
252 :
253 : /* Associating request types with the corresponding request
254 : handlers. */
255 :
256 : static ssh_request_spec_t request_specs[] =
257 : {
258 : #define REQUEST_SPEC_DEFINE(id, name, secret_input) \
259 : { SSH_REQUEST_##id, ssh_handler_##name, #name, secret_input }
260 :
261 : REQUEST_SPEC_DEFINE (REQUEST_IDENTITIES, request_identities, 1),
262 : REQUEST_SPEC_DEFINE (SIGN_REQUEST, sign_request, 0),
263 : REQUEST_SPEC_DEFINE (ADD_IDENTITY, add_identity, 1),
264 : REQUEST_SPEC_DEFINE (ADD_ID_CONSTRAINED, add_identity, 1),
265 : REQUEST_SPEC_DEFINE (REMOVE_IDENTITY, remove_identity, 0),
266 : REQUEST_SPEC_DEFINE (REMOVE_ALL_IDENTITIES, remove_all_identities, 0),
267 : REQUEST_SPEC_DEFINE (LOCK, lock, 0),
268 : REQUEST_SPEC_DEFINE (UNLOCK, unlock, 0)
269 : #undef REQUEST_SPEC_DEFINE
270 : };
271 :
272 :
273 : /* Table holding key type specifications. */
274 : static ssh_key_type_spec_t ssh_key_types[] =
275 : {
276 : {
277 : "ssh-ed25519", "Ed25519", "ecc", "qd", "q", "rs", "qd",
278 : NULL, ssh_signature_encoder_eddsa,
279 : "Ed25519", 0, SPEC_FLAG_IS_EdDSA
280 : },
281 : {
282 : "ssh-rsa", "RSA", "rsa", "nedupq", "en", "s", "nedpqu",
283 : ssh_key_modifier_rsa, ssh_signature_encoder_rsa,
284 : NULL, 0, SPEC_FLAG_USE_PKCS1V2
285 : },
286 : {
287 : "ssh-dss", "DSA", "dsa", "pqgyx", "pqgy", "rs", "pqgyx",
288 : NULL, ssh_signature_encoder_dsa,
289 : NULL, 0, 0
290 : },
291 : {
292 : "ecdsa-sha2-nistp256", "ECDSA", "ecdsa", "qd", "q", "rs", "qd",
293 : NULL, ssh_signature_encoder_ecdsa,
294 : "nistp256", GCRY_MD_SHA256, SPEC_FLAG_IS_ECDSA
295 : },
296 : {
297 : "ecdsa-sha2-nistp384", "ECDSA", "ecdsa", "qd", "q", "rs", "qd",
298 : NULL, ssh_signature_encoder_ecdsa,
299 : "nistp384", GCRY_MD_SHA384, SPEC_FLAG_IS_ECDSA
300 : },
301 : {
302 : "ecdsa-sha2-nistp521", "ECDSA", "ecdsa", "qd", "q", "rs", "qd",
303 : NULL, ssh_signature_encoder_ecdsa,
304 : "nistp521", GCRY_MD_SHA512, SPEC_FLAG_IS_ECDSA
305 : }
306 : };
307 :
308 :
309 :
310 :
311 :
312 : /*
313 : General utility functions.
314 : */
315 :
316 : /* A secure realloc, i.e. it makes sure to allocate secure memory if A
317 : is NULL. This is required because the standard gcry_realloc does
318 : not know whether to allocate secure or normal if NULL is passed as
319 : existing buffer. */
320 : static void *
321 0 : realloc_secure (void *a, size_t n)
322 : {
323 : void *p;
324 :
325 0 : if (a)
326 0 : p = gcry_realloc (a, n);
327 : else
328 0 : p = gcry_malloc_secure (n);
329 :
330 0 : return p;
331 : }
332 :
333 :
334 : /* Create and return a new C-string from DATA/DATA_N (i.e.: add
335 : NUL-termination); return NULL on OOM. */
336 : static char *
337 0 : make_cstring (const char *data, size_t data_n)
338 : {
339 : char *s;
340 :
341 0 : s = xtrymalloc (data_n + 1);
342 0 : if (s)
343 : {
344 0 : memcpy (s, data, data_n);
345 0 : s[data_n] = 0;
346 : }
347 :
348 0 : return s;
349 : }
350 :
351 : /* Lookup the ssh-identifier for the ECC curve CURVE_NAME. Returns
352 : NULL if not found. */
353 : static const char *
354 0 : ssh_identifier_from_curve_name (const char *curve_name)
355 : {
356 : int i;
357 :
358 0 : for (i = 0; i < DIM (ssh_key_types); i++)
359 0 : if (ssh_key_types[i].curve_name
360 0 : && !strcmp (ssh_key_types[i].curve_name, curve_name))
361 0 : return ssh_key_types[i].ssh_identifier;
362 :
363 0 : return NULL;
364 : }
365 :
366 :
367 : /*
368 : Primitive I/O functions.
369 : */
370 :
371 :
372 : /* Read a byte from STREAM, store it in B. */
373 : static gpg_error_t
374 0 : stream_read_byte (estream_t stream, unsigned char *b)
375 : {
376 : gpg_error_t err;
377 : int ret;
378 :
379 0 : ret = es_fgetc (stream);
380 0 : if (ret == EOF)
381 : {
382 0 : if (es_ferror (stream))
383 0 : err = gpg_error_from_syserror ();
384 : else
385 0 : err = gpg_error (GPG_ERR_EOF);
386 0 : *b = 0;
387 : }
388 : else
389 : {
390 0 : *b = ret & 0xFF;
391 0 : err = 0;
392 : }
393 :
394 0 : return err;
395 : }
396 :
397 : /* Write the byte contained in B to STREAM. */
398 : static gpg_error_t
399 0 : stream_write_byte (estream_t stream, unsigned char b)
400 : {
401 : gpg_error_t err;
402 : int ret;
403 :
404 0 : ret = es_fputc (b, stream);
405 0 : if (ret == EOF)
406 0 : err = gpg_error_from_syserror ();
407 : else
408 0 : err = 0;
409 :
410 0 : return err;
411 : }
412 :
413 :
414 : /* Read a uint32 from STREAM, store it in UINT32. */
415 : static gpg_error_t
416 0 : stream_read_uint32 (estream_t stream, u32 *uint32)
417 : {
418 : unsigned char buffer[4];
419 : size_t bytes_read;
420 : gpg_error_t err;
421 : int ret;
422 :
423 0 : ret = es_read (stream, buffer, sizeof (buffer), &bytes_read);
424 0 : if (ret)
425 0 : err = gpg_error_from_syserror ();
426 : else
427 : {
428 0 : if (bytes_read != sizeof (buffer))
429 0 : err = gpg_error (GPG_ERR_EOF);
430 : else
431 : {
432 : u32 n;
433 :
434 0 : n = uint32_construct (buffer[0], buffer[1], buffer[2], buffer[3]);
435 0 : *uint32 = n;
436 0 : err = 0;
437 : }
438 : }
439 :
440 0 : return err;
441 : }
442 :
443 : /* Write the uint32 contained in UINT32 to STREAM. */
444 : static gpg_error_t
445 0 : stream_write_uint32 (estream_t stream, u32 uint32)
446 : {
447 : unsigned char buffer[4];
448 : gpg_error_t err;
449 : int ret;
450 :
451 0 : buffer[0] = uint32 >> 24;
452 0 : buffer[1] = uint32 >> 16;
453 0 : buffer[2] = uint32 >> 8;
454 0 : buffer[3] = uint32 >> 0;
455 :
456 0 : ret = es_write (stream, buffer, sizeof (buffer), NULL);
457 0 : if (ret)
458 0 : err = gpg_error_from_syserror ();
459 : else
460 0 : err = 0;
461 :
462 0 : return err;
463 : }
464 :
465 : /* Read SIZE bytes from STREAM into BUFFER. */
466 : static gpg_error_t
467 0 : stream_read_data (estream_t stream, unsigned char *buffer, size_t size)
468 : {
469 : gpg_error_t err;
470 : size_t bytes_read;
471 : int ret;
472 :
473 0 : ret = es_read (stream, buffer, size, &bytes_read);
474 0 : if (ret)
475 0 : err = gpg_error_from_syserror ();
476 : else
477 : {
478 0 : if (bytes_read != size)
479 0 : err = gpg_error (GPG_ERR_EOF);
480 : else
481 0 : err = 0;
482 : }
483 :
484 0 : return err;
485 : }
486 :
487 : /* Skip over SIZE bytes from STREAM. */
488 : static gpg_error_t
489 0 : stream_read_skip (estream_t stream, size_t size)
490 : {
491 : char buffer[128];
492 : size_t bytes_to_read, bytes_read;
493 : int ret;
494 :
495 : do
496 : {
497 0 : bytes_to_read = size;
498 0 : if (bytes_to_read > sizeof buffer)
499 0 : bytes_to_read = sizeof buffer;
500 :
501 0 : ret = es_read (stream, buffer, bytes_to_read, &bytes_read);
502 0 : if (ret)
503 0 : return gpg_error_from_syserror ();
504 0 : else if (bytes_read != bytes_to_read)
505 0 : return gpg_error (GPG_ERR_EOF);
506 : else
507 0 : size -= bytes_to_read;
508 : }
509 0 : while (size);
510 :
511 0 : return 0;
512 : }
513 :
514 :
515 : /* Write SIZE bytes from BUFFER to STREAM. */
516 : static gpg_error_t
517 0 : stream_write_data (estream_t stream, const unsigned char *buffer, size_t size)
518 : {
519 : gpg_error_t err;
520 : int ret;
521 :
522 0 : ret = es_write (stream, buffer, size, NULL);
523 0 : if (ret)
524 0 : err = gpg_error_from_syserror ();
525 : else
526 0 : err = 0;
527 :
528 0 : return err;
529 : }
530 :
531 : /* Read a binary string from STREAM into STRING, store size of string
532 : in STRING_SIZE. Append a hidden nul so that the result may
533 : directly be used as a C string. Depending on SECURE use secure
534 : memory for STRING. */
535 : static gpg_error_t
536 0 : stream_read_string (estream_t stream, unsigned int secure,
537 : unsigned char **string, u32 *string_size)
538 : {
539 : gpg_error_t err;
540 0 : unsigned char *buffer = NULL;
541 0 : u32 length = 0;
542 :
543 0 : if (string_size)
544 0 : *string_size = 0;
545 :
546 : /* Read string length. */
547 0 : err = stream_read_uint32 (stream, &length);
548 0 : if (err)
549 0 : goto out;
550 :
551 : /* Allocate space. */
552 0 : if (secure)
553 0 : buffer = xtrymalloc_secure (length + 1);
554 : else
555 0 : buffer = xtrymalloc (length + 1);
556 0 : if (! buffer)
557 : {
558 0 : err = gpg_error_from_syserror ();
559 0 : goto out;
560 : }
561 :
562 : /* Read data. */
563 0 : err = stream_read_data (stream, buffer, length);
564 0 : if (err)
565 0 : goto out;
566 :
567 : /* Finalize string object. */
568 0 : buffer[length] = 0;
569 0 : *string = buffer;
570 0 : if (string_size)
571 0 : *string_size = length;
572 :
573 : out:
574 :
575 0 : if (err)
576 0 : xfree (buffer);
577 :
578 0 : return err;
579 : }
580 :
581 :
582 : /* Read a binary string from STREAM and store it as an opaque MPI at
583 : R_MPI, adding 0x40 (this is the prefix for EdDSA key in OpenPGP).
584 : Depending on SECURE use secure memory. If the string is too large
585 : for key material return an error. */
586 : static gpg_error_t
587 0 : stream_read_blob (estream_t stream, unsigned int secure, gcry_mpi_t *r_mpi)
588 : {
589 : gpg_error_t err;
590 0 : unsigned char *buffer = NULL;
591 0 : u32 length = 0;
592 :
593 0 : *r_mpi = NULL;
594 :
595 : /* Read string length. */
596 0 : err = stream_read_uint32 (stream, &length);
597 0 : if (err)
598 0 : goto leave;
599 :
600 : /* To avoid excessive use of secure memory we check that an MPI is
601 : not too large. */
602 0 : if (length > (4096/8) + 8)
603 : {
604 0 : log_error (_("ssh keys greater than %d bits are not supported\n"), 4096);
605 0 : err = GPG_ERR_TOO_LARGE;
606 0 : goto leave;
607 : }
608 :
609 : /* Allocate space. */
610 0 : if (secure)
611 0 : buffer = xtrymalloc_secure (length+1);
612 : else
613 0 : buffer = xtrymalloc (length+1);
614 0 : if (!buffer)
615 : {
616 0 : err = gpg_error_from_syserror ();
617 0 : goto leave;
618 : }
619 :
620 : /* Read data. */
621 0 : err = stream_read_data (stream, buffer + 1, length);
622 0 : if (err)
623 0 : goto leave;
624 :
625 0 : buffer[0] = 0x40;
626 0 : *r_mpi = gcry_mpi_set_opaque (NULL, buffer, 8*(length+1));
627 0 : buffer = NULL;
628 :
629 : leave:
630 0 : xfree (buffer);
631 0 : return err;
632 : }
633 :
634 :
635 : /* Read a C-string from STREAM, store copy in STRING. */
636 : static gpg_error_t
637 0 : stream_read_cstring (estream_t stream, char **string)
638 : {
639 : gpg_error_t err;
640 : unsigned char *buffer;
641 :
642 0 : err = stream_read_string (stream, 0, &buffer, NULL);
643 0 : if (!err)
644 0 : *string = (char *)buffer;
645 0 : return err;
646 : }
647 :
648 :
649 : /* Write a binary string from STRING of size STRING_N to STREAM. */
650 : static gpg_error_t
651 0 : stream_write_string (estream_t stream,
652 : const unsigned char *string, u32 string_n)
653 : {
654 : gpg_error_t err;
655 :
656 0 : err = stream_write_uint32 (stream, string_n);
657 0 : if (err)
658 0 : goto out;
659 :
660 0 : err = stream_write_data (stream, string, string_n);
661 :
662 : out:
663 :
664 0 : return err;
665 : }
666 :
667 : /* Write a C-string from STRING to STREAM. */
668 : static gpg_error_t
669 0 : stream_write_cstring (estream_t stream, const char *string)
670 : {
671 : gpg_error_t err;
672 :
673 0 : err = stream_write_string (stream,
674 0 : (const unsigned char *) string, strlen (string));
675 :
676 0 : return err;
677 : }
678 :
679 : /* Read an MPI from STREAM, store it in MPINT. Depending on SECURE
680 : use secure memory. */
681 : static gpg_error_t
682 0 : stream_read_mpi (estream_t stream, unsigned int secure, gcry_mpi_t *mpint)
683 : {
684 : unsigned char *mpi_data;
685 : u32 mpi_data_size;
686 : gpg_error_t err;
687 : gcry_mpi_t mpi;
688 :
689 0 : mpi_data = NULL;
690 :
691 0 : err = stream_read_string (stream, secure, &mpi_data, &mpi_data_size);
692 0 : if (err)
693 0 : goto out;
694 :
695 : /* To avoid excessive use of secure memory we check that an MPI is
696 : not too large. */
697 0 : if (mpi_data_size > 520)
698 : {
699 0 : log_error (_("ssh keys greater than %d bits are not supported\n"), 4096);
700 0 : err = GPG_ERR_TOO_LARGE;
701 0 : goto out;
702 : }
703 :
704 0 : err = gcry_mpi_scan (&mpi, GCRYMPI_FMT_STD, mpi_data, mpi_data_size, NULL);
705 0 : if (err)
706 0 : goto out;
707 :
708 0 : *mpint = mpi;
709 :
710 : out:
711 :
712 0 : xfree (mpi_data);
713 :
714 0 : return err;
715 : }
716 :
717 : /* Write the MPI contained in MPINT to STREAM. */
718 : static gpg_error_t
719 0 : stream_write_mpi (estream_t stream, gcry_mpi_t mpint)
720 : {
721 : unsigned char *mpi_buffer;
722 : size_t mpi_buffer_n;
723 : gpg_error_t err;
724 :
725 0 : mpi_buffer = NULL;
726 :
727 0 : err = gcry_mpi_aprint (GCRYMPI_FMT_STD, &mpi_buffer, &mpi_buffer_n, mpint);
728 0 : if (err)
729 0 : goto out;
730 :
731 0 : err = stream_write_string (stream, mpi_buffer, mpi_buffer_n);
732 :
733 : out:
734 :
735 0 : xfree (mpi_buffer);
736 :
737 0 : return err;
738 : }
739 :
740 :
741 : /* Copy data from SRC to DST until EOF is reached. */
742 : static gpg_error_t
743 0 : stream_copy (estream_t dst, estream_t src)
744 : {
745 : char buffer[BUFSIZ];
746 : size_t bytes_read;
747 : gpg_error_t err;
748 : int ret;
749 :
750 0 : err = 0;
751 : while (1)
752 : {
753 0 : ret = es_read (src, buffer, sizeof (buffer), &bytes_read);
754 0 : if (ret || (! bytes_read))
755 : {
756 0 : if (ret)
757 0 : err = gpg_error_from_syserror ();
758 0 : break;
759 : }
760 0 : ret = es_write (dst, buffer, bytes_read, NULL);
761 0 : if (ret)
762 : {
763 0 : err = gpg_error_from_syserror ();
764 0 : break;
765 : }
766 0 : }
767 :
768 0 : return err;
769 : }
770 :
771 :
772 : /* Read the content of the file specified by FILENAME into a newly
773 : create buffer, which is to be stored in BUFFER; store length of
774 : buffer in BUFFER_N. */
775 : static gpg_error_t
776 0 : file_to_buffer (const char *filename, unsigned char **buffer, size_t *buffer_n)
777 : {
778 : unsigned char *buffer_new;
779 : struct stat statbuf;
780 : estream_t stream;
781 : gpg_error_t err;
782 : int ret;
783 :
784 0 : *buffer = NULL;
785 0 : *buffer_n = 0;
786 :
787 0 : buffer_new = NULL;
788 0 : err = 0;
789 :
790 0 : stream = es_fopen (filename, "rb");
791 0 : if (! stream)
792 : {
793 0 : err = gpg_error_from_syserror ();
794 0 : goto out;
795 : }
796 :
797 0 : ret = fstat (es_fileno (stream), &statbuf);
798 0 : if (ret)
799 : {
800 0 : err = gpg_error_from_syserror ();
801 0 : goto out;
802 : }
803 :
804 0 : buffer_new = xtrymalloc (statbuf.st_size);
805 0 : if (! buffer_new)
806 : {
807 0 : err = gpg_error_from_syserror ();
808 0 : goto out;
809 : }
810 :
811 0 : err = stream_read_data (stream, buffer_new, statbuf.st_size);
812 0 : if (err)
813 0 : goto out;
814 :
815 0 : *buffer = buffer_new;
816 0 : *buffer_n = statbuf.st_size;
817 :
818 : out:
819 :
820 0 : if (stream)
821 0 : es_fclose (stream);
822 :
823 0 : if (err)
824 0 : xfree (buffer_new);
825 :
826 0 : return err;
827 : }
828 :
829 :
830 :
831 :
832 : /* Open the ssh control file and create it if not available. With
833 : APPEND passed as true the file will be opened in append mode,
834 : otherwise in read only mode. On success 0 is returned and a new
835 : control file object stored at R_CF. On error an error code is
836 : returned and NULL is stored at R_CF. */
837 : static gpg_error_t
838 0 : open_control_file (ssh_control_file_t *r_cf, int append)
839 : {
840 : gpg_error_t err;
841 : ssh_control_file_t cf;
842 :
843 0 : cf = xtrycalloc (1, sizeof *cf);
844 0 : if (!cf)
845 : {
846 0 : err = gpg_error_from_syserror ();
847 0 : goto leave;
848 : }
849 :
850 : /* Note: As soon as we start to use non blocking functions here
851 : (i.e. where Pth might switch threads) we need to employ a
852 : mutex. */
853 0 : cf->fname = make_filename_try (opt.homedir, SSH_CONTROL_FILE_NAME, NULL);
854 0 : if (!cf->fname)
855 : {
856 0 : err = gpg_error_from_syserror ();
857 0 : goto leave;
858 : }
859 : /* FIXME: With "a+" we are not able to check whether this will
860 : be created and thus the blurb needs to be written first. */
861 0 : cf->fp = fopen (cf->fname, append? "a+":"r");
862 0 : if (!cf->fp && errno == ENOENT)
863 : {
864 0 : estream_t stream = es_fopen (cf->fname, "wx,mode=-rw-r");
865 0 : if (!stream)
866 : {
867 0 : err = gpg_error_from_syserror ();
868 0 : log_error (_("can't create '%s': %s\n"),
869 : cf->fname, gpg_strerror (err));
870 0 : goto leave;
871 : }
872 0 : es_fputs (sshcontrolblurb, stream);
873 0 : es_fclose (stream);
874 0 : cf->fp = fopen (cf->fname, append? "a+":"r");
875 : }
876 :
877 0 : if (!cf->fp)
878 : {
879 0 : err = gpg_error_from_syserror ();
880 0 : log_error (_("can't open '%s': %s\n"),
881 : cf->fname, gpg_strerror (err));
882 0 : goto leave;
883 : }
884 :
885 0 : err = 0;
886 :
887 : leave:
888 0 : if (err && cf)
889 : {
890 0 : if (cf->fp)
891 0 : fclose (cf->fp);
892 0 : xfree (cf->fname);
893 0 : xfree (cf);
894 : }
895 : else
896 0 : *r_cf = cf;
897 :
898 0 : return err;
899 : }
900 :
901 :
902 : static void
903 0 : rewind_control_file (ssh_control_file_t cf)
904 : {
905 0 : fseek (cf->fp, 0, SEEK_SET);
906 0 : cf->lnr = 0;
907 0 : clearerr (cf->fp);
908 0 : }
909 :
910 :
911 : static void
912 0 : close_control_file (ssh_control_file_t cf)
913 : {
914 0 : if (!cf)
915 0 : return;
916 0 : fclose (cf->fp);
917 0 : xfree (cf->fname);
918 0 : xfree (cf);
919 : }
920 :
921 :
922 :
923 : /* Read the next line from the control file and store the data in CF.
924 : Returns 0 on success, GPG_ERR_EOF on EOF, or other error codes. */
925 : static gpg_error_t
926 0 : read_control_file_item (ssh_control_file_t cf)
927 : {
928 : int c, i, n;
929 : char *p, *pend, line[256];
930 0 : long ttl = 0;
931 :
932 0 : cf->item.valid = 0;
933 0 : clearerr (cf->fp);
934 :
935 : do
936 : {
937 0 : if (!fgets (line, DIM(line)-1, cf->fp) )
938 : {
939 0 : if (feof (cf->fp))
940 0 : return gpg_error (GPG_ERR_EOF);
941 0 : return gpg_error_from_syserror ();
942 : }
943 0 : cf->lnr++;
944 :
945 0 : if (!*line || line[strlen(line)-1] != '\n')
946 : {
947 : /* Eat until end of line */
948 0 : while ( (c=getc (cf->fp)) != EOF && c != '\n')
949 : ;
950 0 : return gpg_error (*line? GPG_ERR_LINE_TOO_LONG
951 : : GPG_ERR_INCOMPLETE_LINE);
952 : }
953 :
954 : /* Allow for empty lines and spaces */
955 0 : for (p=line; spacep (p); p++)
956 : ;
957 : }
958 0 : while (!*p || *p == '\n' || *p == '#');
959 :
960 0 : cf->item.disabled = 0;
961 0 : if (*p == '!')
962 : {
963 0 : cf->item.disabled = 1;
964 0 : for (p++; spacep (p); p++)
965 : ;
966 : }
967 :
968 0 : for (i=0; hexdigitp (p) && i < 40; p++, i++)
969 0 : cf->item.hexgrip[i] = (*p >= 'a'? (*p & 0xdf): *p);
970 0 : cf->item.hexgrip[i] = 0;
971 0 : if (i != 40 || !(spacep (p) || *p == '\n'))
972 : {
973 0 : log_error ("%s:%d: invalid formatted line\n", cf->fname, cf->lnr);
974 0 : return gpg_error (GPG_ERR_BAD_DATA);
975 : }
976 :
977 0 : ttl = strtol (p, &pend, 10);
978 0 : p = pend;
979 0 : if (!(spacep (p) || *p == '\n') || (int)ttl < -1)
980 : {
981 0 : log_error ("%s:%d: invalid TTL value; assuming 0\n", cf->fname, cf->lnr);
982 0 : cf->item.ttl = 0;
983 : }
984 0 : cf->item.ttl = ttl;
985 :
986 : /* Now check for key-value pairs of the form NAME[=VALUE]. */
987 0 : cf->item.confirm = 0;
988 0 : while (*p)
989 : {
990 0 : for (; spacep (p) && *p != '\n'; p++)
991 : ;
992 0 : if (!*p || *p == '\n')
993 : break;
994 0 : n = strcspn (p, "= \t\n");
995 0 : if (p[n] == '=')
996 : {
997 0 : log_error ("%s:%d: assigning a value to a flag is not yet supported; "
998 : "flag ignored\n", cf->fname, cf->lnr);
999 0 : p++;
1000 : }
1001 0 : else if (n == 7 && !memcmp (p, "confirm", 7))
1002 : {
1003 0 : cf->item.confirm = 1;
1004 : }
1005 : else
1006 0 : log_error ("%s:%d: invalid flag '%.*s'; ignored\n",
1007 : cf->fname, cf->lnr, n, p);
1008 0 : p += n;
1009 : }
1010 :
1011 : /* log_debug ("%s:%d: grip=%s ttl=%d%s%s\n", */
1012 : /* cf->fname, cf->lnr, */
1013 : /* cf->item.hexgrip, cf->item.ttl, */
1014 : /* cf->item.disabled? " disabled":"", */
1015 : /* cf->item.confirm? " confirm":""); */
1016 :
1017 0 : cf->item.valid = 1;
1018 0 : return 0; /* Okay: valid entry found. */
1019 : }
1020 :
1021 :
1022 :
1023 : /* Search the control file CF from the beginning until a matching
1024 : HEXGRIP is found; return success in this case and store true at
1025 : DISABLED if the found key has been disabled. If R_TTL is not NULL
1026 : a specified TTL for that key is stored there. If R_CONFIRM is not
1027 : NULL it is set to 1 if the key has the confirm flag set. */
1028 : static gpg_error_t
1029 0 : search_control_file (ssh_control_file_t cf, const char *hexgrip,
1030 : int *r_disabled, int *r_ttl, int *r_confirm)
1031 : {
1032 : gpg_error_t err;
1033 :
1034 0 : assert (strlen (hexgrip) == 40 );
1035 :
1036 0 : if (r_disabled)
1037 0 : *r_disabled = 0;
1038 0 : if (r_ttl)
1039 0 : *r_ttl = 0;
1040 0 : if (r_confirm)
1041 0 : *r_confirm = 0;
1042 :
1043 0 : rewind_control_file (cf);
1044 0 : while (!(err=read_control_file_item (cf)))
1045 : {
1046 0 : if (!cf->item.valid)
1047 0 : continue; /* Should not happen. */
1048 0 : if (!strcmp (hexgrip, cf->item.hexgrip))
1049 0 : break;
1050 : }
1051 0 : if (!err)
1052 : {
1053 0 : if (r_disabled)
1054 0 : *r_disabled = cf->item.disabled;
1055 0 : if (r_ttl)
1056 0 : *r_ttl = cf->item.ttl;
1057 0 : if (r_confirm)
1058 0 : *r_confirm = cf->item.confirm;
1059 : }
1060 0 : return err;
1061 : }
1062 :
1063 :
1064 :
1065 : /* Add an entry to the control file to mark the key with the keygrip
1066 : HEXGRIP as usable for SSH; i.e. it will be returned when ssh asks
1067 : for it. FMTFPR is the fingerprint string. This function is in
1068 : general used to add a key received through the ssh-add function.
1069 : We can assume that the user wants to allow ssh using this key. */
1070 : static gpg_error_t
1071 0 : add_control_entry (ctrl_t ctrl, ssh_key_type_spec_t *spec,
1072 : const char *hexgrip, const char *fmtfpr,
1073 : int ttl, int confirm)
1074 : {
1075 : gpg_error_t err;
1076 : ssh_control_file_t cf;
1077 : int disabled;
1078 :
1079 : (void)ctrl;
1080 :
1081 0 : err = open_control_file (&cf, 1);
1082 0 : if (err)
1083 0 : return err;
1084 :
1085 0 : err = search_control_file (cf, hexgrip, &disabled, NULL, NULL);
1086 0 : if (err && gpg_err_code(err) == GPG_ERR_EOF)
1087 : {
1088 : struct tm *tp;
1089 0 : time_t atime = time (NULL);
1090 :
1091 : /* Not yet in the file - add it. Because the file has been
1092 : opened in append mode, we simply need to write to it. */
1093 0 : tp = localtime (&atime);
1094 0 : fprintf (cf->fp,
1095 : ("# %s key added on: %04d-%02d-%02d %02d:%02d:%02d\n"
1096 : "# MD5 Fingerprint: %s\n"
1097 : "%s %d%s\n"),
1098 : spec->name,
1099 0 : 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
1100 : tp->tm_hour, tp->tm_min, tp->tm_sec,
1101 : fmtfpr, hexgrip, ttl, confirm? " confirm":"");
1102 :
1103 : }
1104 0 : close_control_file (cf);
1105 0 : return 0;
1106 : }
1107 :
1108 :
1109 : /* Scan the sshcontrol file and return the TTL. */
1110 : static int
1111 0 : ttl_from_sshcontrol (const char *hexgrip)
1112 : {
1113 : ssh_control_file_t cf;
1114 : int disabled, ttl;
1115 :
1116 0 : if (!hexgrip || strlen (hexgrip) != 40)
1117 0 : return 0; /* Wrong input: Use global default. */
1118 :
1119 0 : if (open_control_file (&cf, 0))
1120 0 : return 0; /* Error: Use the global default TTL. */
1121 :
1122 0 : if (search_control_file (cf, hexgrip, &disabled, &ttl, NULL)
1123 0 : || disabled)
1124 0 : ttl = 0; /* Use the global default if not found or disabled. */
1125 :
1126 0 : close_control_file (cf);
1127 :
1128 0 : return ttl;
1129 : }
1130 :
1131 :
1132 : /* Scan the sshcontrol file and return the confirm flag. */
1133 : static int
1134 0 : confirm_flag_from_sshcontrol (const char *hexgrip)
1135 : {
1136 : ssh_control_file_t cf;
1137 : int disabled, confirm;
1138 :
1139 0 : if (!hexgrip || strlen (hexgrip) != 40)
1140 0 : return 1; /* Wrong input: Better ask for confirmation. */
1141 :
1142 0 : if (open_control_file (&cf, 0))
1143 0 : return 1; /* Error: Better ask for confirmation. */
1144 :
1145 0 : if (search_control_file (cf, hexgrip, &disabled, NULL, &confirm)
1146 0 : || disabled)
1147 0 : confirm = 0; /* If not found or disabled, there is no reason to
1148 : ask for confirmation. */
1149 :
1150 0 : close_control_file (cf);
1151 :
1152 0 : return confirm;
1153 : }
1154 :
1155 :
1156 :
1157 :
1158 : /* Open the ssh control file for reading. This is a public version of
1159 : open_control_file. The caller must use ssh_close_control_file to
1160 : release the retruned handle. */
1161 : ssh_control_file_t
1162 0 : ssh_open_control_file (void)
1163 : {
1164 : ssh_control_file_t cf;
1165 :
1166 : /* Then look at all the registered and non-disabled keys. */
1167 0 : if (open_control_file (&cf, 0))
1168 0 : return NULL;
1169 0 : return cf;
1170 : }
1171 :
1172 : /* Close an ssh control file handle. This is the public version of
1173 : close_control_file. CF may be NULL. */
1174 : void
1175 0 : ssh_close_control_file (ssh_control_file_t cf)
1176 : {
1177 0 : close_control_file (cf);
1178 0 : }
1179 :
1180 : /* Read the next item from the ssh control file. The function returns
1181 : 0 if a item was read, GPG_ERR_EOF on eof or another error value.
1182 : R_HEXGRIP shall either be null or a BUFFER of at least 41 byte.
1183 : R_DISABLED, R_TTLm and R_CONFIRM return flags from the control
1184 : file; they are only set on success. */
1185 : gpg_error_t
1186 0 : ssh_read_control_file (ssh_control_file_t cf,
1187 : char *r_hexgrip,
1188 : int *r_disabled, int *r_ttl, int *r_confirm)
1189 : {
1190 : gpg_error_t err;
1191 :
1192 : do
1193 0 : err = read_control_file_item (cf);
1194 0 : while (!err && !cf->item.valid);
1195 0 : if (!err)
1196 : {
1197 0 : if (r_hexgrip)
1198 0 : strcpy (r_hexgrip, cf->item.hexgrip);
1199 0 : if (r_disabled)
1200 0 : *r_disabled = cf->item.disabled;
1201 0 : if (r_ttl)
1202 0 : *r_ttl = cf->item.ttl;
1203 0 : if (r_confirm)
1204 0 : *r_confirm = cf->item.confirm;
1205 : }
1206 0 : return err;
1207 : }
1208 :
1209 :
1210 : /* Search for a key with HEXGRIP in sshcontrol and return all
1211 : info. */
1212 : gpg_error_t
1213 0 : ssh_search_control_file (ssh_control_file_t cf,
1214 : const char *hexgrip,
1215 : int *r_disabled, int *r_ttl, int *r_confirm)
1216 : {
1217 : gpg_error_t err;
1218 : int i;
1219 : const char *s;
1220 : char uphexgrip[41];
1221 :
1222 : /* We need to make sure that HEXGRIP is all uppercase. The easiest
1223 : way to do this and also check its length is by copying to a
1224 : second buffer. */
1225 0 : for (i=0, s=hexgrip; i < 40 && *s; s++, i++)
1226 0 : uphexgrip[i] = *s >= 'a'? (*s & 0xdf): *s;
1227 0 : uphexgrip[i] = 0;
1228 0 : if (i != 40)
1229 0 : err = gpg_error (GPG_ERR_INV_LENGTH);
1230 : else
1231 0 : err = search_control_file (cf, uphexgrip, r_disabled, r_ttl, r_confirm);
1232 0 : if (gpg_err_code (err) == GPG_ERR_EOF)
1233 0 : err = gpg_error (GPG_ERR_NOT_FOUND);
1234 0 : return err;
1235 : }
1236 :
1237 :
1238 :
1239 :
1240 : /*
1241 :
1242 : MPI lists.
1243 :
1244 : */
1245 :
1246 : /* Free the list of MPIs MPI_LIST. */
1247 : static void
1248 0 : mpint_list_free (gcry_mpi_t *mpi_list)
1249 : {
1250 0 : if (mpi_list)
1251 : {
1252 : unsigned int i;
1253 :
1254 0 : for (i = 0; mpi_list[i]; i++)
1255 0 : gcry_mpi_release (mpi_list[i]);
1256 0 : xfree (mpi_list);
1257 : }
1258 0 : }
1259 :
1260 : /* Receive key material MPIs from STREAM according to KEY_SPEC;
1261 : depending on SECRET expect a public key or secret key. The newly
1262 : allocated list of MPIs is stored in MPI_LIST. Returns usual error
1263 : code. */
1264 : static gpg_error_t
1265 0 : ssh_receive_mpint_list (estream_t stream, int secret,
1266 : ssh_key_type_spec_t key_spec, gcry_mpi_t **mpi_list)
1267 : {
1268 : const char *elems_public;
1269 : unsigned int elems_n;
1270 : const char *elems;
1271 : int elem_is_secret;
1272 : gcry_mpi_t *mpis;
1273 : gpg_error_t err;
1274 : unsigned int i;
1275 :
1276 0 : mpis = NULL;
1277 0 : err = 0;
1278 :
1279 0 : if (secret)
1280 0 : elems = key_spec.elems_key_secret;
1281 : else
1282 0 : elems = key_spec.elems_key_public;
1283 0 : elems_n = strlen (elems);
1284 :
1285 0 : elems_public = key_spec.elems_key_public;
1286 :
1287 0 : mpis = xtrycalloc (elems_n + 1, sizeof *mpis );
1288 0 : if (!mpis)
1289 : {
1290 0 : err = gpg_error_from_syserror ();
1291 0 : goto out;
1292 : }
1293 :
1294 0 : elem_is_secret = 0;
1295 0 : for (i = 0; i < elems_n; i++)
1296 : {
1297 0 : if (secret)
1298 0 : elem_is_secret = ! strchr (elems_public, elems[i]);
1299 0 : err = stream_read_mpi (stream, elem_is_secret, &mpis[i]);
1300 0 : if (err)
1301 0 : break;
1302 : }
1303 0 : if (err)
1304 0 : goto out;
1305 :
1306 0 : *mpi_list = mpis;
1307 :
1308 : out:
1309 :
1310 0 : if (err)
1311 0 : mpint_list_free (mpis);
1312 :
1313 0 : return err;
1314 : }
1315 :
1316 :
1317 :
1318 : /* Key modifier function for RSA. */
1319 : static gpg_error_t
1320 0 : ssh_key_modifier_rsa (const char *elems, gcry_mpi_t *mpis)
1321 : {
1322 : gcry_mpi_t p;
1323 : gcry_mpi_t q;
1324 : gcry_mpi_t u;
1325 :
1326 0 : if (strcmp (elems, "nedupq"))
1327 : /* Modifying only necessary for secret keys. */
1328 0 : goto out;
1329 :
1330 0 : u = mpis[3];
1331 0 : p = mpis[4];
1332 0 : q = mpis[5];
1333 :
1334 0 : if (gcry_mpi_cmp (p, q) > 0)
1335 : {
1336 : /* P shall be smaller then Q! Swap primes. iqmp becomes u. */
1337 : gcry_mpi_t tmp;
1338 :
1339 0 : tmp = mpis[4];
1340 0 : mpis[4] = mpis[5];
1341 0 : mpis[5] = tmp;
1342 : }
1343 : else
1344 : /* U needs to be recomputed. */
1345 0 : gcry_mpi_invm (u, p, q);
1346 :
1347 : out:
1348 :
1349 0 : return 0;
1350 : }
1351 :
1352 : /* Signature encoder function for RSA. */
1353 : static gpg_error_t
1354 0 : ssh_signature_encoder_rsa (ssh_key_type_spec_t *spec,
1355 : estream_t signature_blob,
1356 : gcry_sexp_t s_signature)
1357 : {
1358 0 : gpg_error_t err = 0;
1359 0 : gcry_sexp_t valuelist = NULL;
1360 0 : gcry_sexp_t sublist = NULL;
1361 0 : gcry_mpi_t sig_value = NULL;
1362 0 : gcry_mpi_t *mpis = NULL;
1363 : const char *elems;
1364 : size_t elems_n;
1365 : int i;
1366 :
1367 : unsigned char *data;
1368 : size_t data_n;
1369 : gcry_mpi_t s;
1370 :
1371 0 : valuelist = gcry_sexp_nth (s_signature, 1);
1372 0 : if (!valuelist)
1373 : {
1374 0 : err = gpg_error (GPG_ERR_INV_SEXP);
1375 0 : goto out;
1376 : }
1377 :
1378 0 : elems = spec->elems_signature;
1379 0 : elems_n = strlen (elems);
1380 :
1381 0 : mpis = xtrycalloc (elems_n + 1, sizeof *mpis);
1382 0 : if (!mpis)
1383 : {
1384 0 : err = gpg_error_from_syserror ();
1385 0 : goto out;
1386 : }
1387 :
1388 0 : for (i = 0; i < elems_n; i++)
1389 : {
1390 0 : sublist = gcry_sexp_find_token (valuelist, spec->elems_signature + i, 1);
1391 0 : if (!sublist)
1392 : {
1393 0 : err = gpg_error (GPG_ERR_INV_SEXP);
1394 0 : break;
1395 : }
1396 :
1397 0 : sig_value = gcry_sexp_nth_mpi (sublist, 1, GCRYMPI_FMT_USG);
1398 0 : if (!sig_value)
1399 : {
1400 0 : err = gpg_error (GPG_ERR_INTERNAL); /* FIXME? */
1401 0 : break;
1402 : }
1403 0 : gcry_sexp_release (sublist);
1404 0 : sublist = NULL;
1405 :
1406 0 : mpis[i] = sig_value;
1407 : }
1408 0 : if (err)
1409 0 : goto out;
1410 :
1411 : /* RSA specific */
1412 0 : s = mpis[0];
1413 :
1414 0 : err = gcry_mpi_aprint (GCRYMPI_FMT_USG, &data, &data_n, s);
1415 0 : if (err)
1416 0 : goto out;
1417 :
1418 0 : err = stream_write_string (signature_blob, data, data_n);
1419 0 : xfree (data);
1420 :
1421 : out:
1422 0 : gcry_sexp_release (valuelist);
1423 0 : gcry_sexp_release (sublist);
1424 0 : mpint_list_free (mpis);
1425 0 : return err;
1426 : }
1427 :
1428 :
1429 : /* Signature encoder function for DSA. */
1430 : static gpg_error_t
1431 0 : ssh_signature_encoder_dsa (ssh_key_type_spec_t *spec,
1432 : estream_t signature_blob,
1433 : gcry_sexp_t s_signature)
1434 : {
1435 0 : gpg_error_t err = 0;
1436 0 : gcry_sexp_t valuelist = NULL;
1437 0 : gcry_sexp_t sublist = NULL;
1438 0 : gcry_mpi_t sig_value = NULL;
1439 0 : gcry_mpi_t *mpis = NULL;
1440 : const char *elems;
1441 : size_t elems_n;
1442 : int i;
1443 :
1444 : unsigned char buffer[SSH_DSA_SIGNATURE_PADDING * SSH_DSA_SIGNATURE_ELEMS];
1445 0 : unsigned char *data = NULL;
1446 : size_t data_n;
1447 :
1448 0 : valuelist = gcry_sexp_nth (s_signature, 1);
1449 0 : if (!valuelist)
1450 : {
1451 0 : err = gpg_error (GPG_ERR_INV_SEXP);
1452 0 : goto out;
1453 : }
1454 :
1455 0 : elems = spec->elems_signature;
1456 0 : elems_n = strlen (elems);
1457 :
1458 0 : mpis = xtrycalloc (elems_n + 1, sizeof *mpis);
1459 0 : if (!mpis)
1460 : {
1461 0 : err = gpg_error_from_syserror ();
1462 0 : goto out;
1463 : }
1464 :
1465 0 : for (i = 0; i < elems_n; i++)
1466 : {
1467 0 : sublist = gcry_sexp_find_token (valuelist, spec->elems_signature + i, 1);
1468 0 : if (!sublist)
1469 : {
1470 0 : err = gpg_error (GPG_ERR_INV_SEXP);
1471 0 : break;
1472 : }
1473 :
1474 0 : sig_value = gcry_sexp_nth_mpi (sublist, 1, GCRYMPI_FMT_USG);
1475 0 : if (!sig_value)
1476 : {
1477 0 : err = gpg_error (GPG_ERR_INTERNAL); /* FIXME? */
1478 0 : break;
1479 : }
1480 0 : gcry_sexp_release (sublist);
1481 0 : sublist = NULL;
1482 :
1483 0 : mpis[i] = sig_value;
1484 : }
1485 0 : if (err)
1486 0 : goto out;
1487 :
1488 : /* DSA specific code. */
1489 :
1490 : /* FIXME: Why this complicated code? Why collecting boths mpis in a
1491 : buffer instead of writing them out one after the other? */
1492 0 : for (i = 0; i < 2; i++)
1493 : {
1494 0 : err = gcry_mpi_aprint (GCRYMPI_FMT_USG, &data, &data_n, mpis[i]);
1495 0 : if (err)
1496 0 : break;
1497 :
1498 0 : if (data_n > SSH_DSA_SIGNATURE_PADDING)
1499 : {
1500 0 : err = gpg_error (GPG_ERR_INTERNAL); /* FIXME? */
1501 0 : break;
1502 : }
1503 :
1504 0 : memset (buffer + (i * SSH_DSA_SIGNATURE_PADDING), 0,
1505 : SSH_DSA_SIGNATURE_PADDING - data_n);
1506 0 : memcpy (buffer + (i * SSH_DSA_SIGNATURE_PADDING)
1507 0 : + (SSH_DSA_SIGNATURE_PADDING - data_n), data, data_n);
1508 :
1509 0 : xfree (data);
1510 0 : data = NULL;
1511 : }
1512 0 : if (err)
1513 0 : goto out;
1514 :
1515 0 : err = stream_write_string (signature_blob, buffer, sizeof (buffer));
1516 :
1517 : out:
1518 0 : xfree (data);
1519 0 : gcry_sexp_release (valuelist);
1520 0 : gcry_sexp_release (sublist);
1521 0 : mpint_list_free (mpis);
1522 0 : return err;
1523 : }
1524 :
1525 :
1526 : /* Signature encoder function for ECDSA. */
1527 : static gpg_error_t
1528 0 : ssh_signature_encoder_ecdsa (ssh_key_type_spec_t *spec,
1529 : estream_t stream, gcry_sexp_t s_signature)
1530 : {
1531 0 : gpg_error_t err = 0;
1532 0 : gcry_sexp_t valuelist = NULL;
1533 0 : gcry_sexp_t sublist = NULL;
1534 0 : gcry_mpi_t sig_value = NULL;
1535 0 : gcry_mpi_t *mpis = NULL;
1536 : const char *elems;
1537 : size_t elems_n;
1538 : int i;
1539 :
1540 0 : unsigned char *data[2] = {NULL, NULL};
1541 : size_t data_n[2];
1542 : size_t innerlen;
1543 :
1544 0 : valuelist = gcry_sexp_nth (s_signature, 1);
1545 0 : if (!valuelist)
1546 : {
1547 0 : err = gpg_error (GPG_ERR_INV_SEXP);
1548 0 : goto out;
1549 : }
1550 :
1551 0 : elems = spec->elems_signature;
1552 0 : elems_n = strlen (elems);
1553 :
1554 0 : mpis = xtrycalloc (elems_n + 1, sizeof *mpis);
1555 0 : if (!mpis)
1556 : {
1557 0 : err = gpg_error_from_syserror ();
1558 0 : goto out;
1559 : }
1560 :
1561 0 : for (i = 0; i < elems_n; i++)
1562 : {
1563 0 : sublist = gcry_sexp_find_token (valuelist, spec->elems_signature + i, 1);
1564 0 : if (!sublist)
1565 : {
1566 0 : err = gpg_error (GPG_ERR_INV_SEXP);
1567 0 : break;
1568 : }
1569 :
1570 0 : sig_value = gcry_sexp_nth_mpi (sublist, 1, GCRYMPI_FMT_USG);
1571 0 : if (!sig_value)
1572 : {
1573 0 : err = gpg_error (GPG_ERR_INTERNAL); /* FIXME? */
1574 0 : break;
1575 : }
1576 0 : gcry_sexp_release (sublist);
1577 0 : sublist = NULL;
1578 :
1579 0 : mpis[i] = sig_value;
1580 : }
1581 0 : if (err)
1582 0 : goto out;
1583 :
1584 : /* ECDSA specific */
1585 :
1586 0 : innerlen = 0;
1587 0 : for (i = 0; i < DIM(data); i++)
1588 : {
1589 0 : err = gcry_mpi_aprint (GCRYMPI_FMT_STD, &data[i], &data_n[i], mpis[i]);
1590 0 : if (err)
1591 0 : goto out;
1592 0 : innerlen += 4 + data_n[i];
1593 : }
1594 :
1595 0 : err = stream_write_uint32 (stream, innerlen);
1596 0 : if (err)
1597 0 : goto out;
1598 :
1599 0 : for (i = 0; i < DIM(data); i++)
1600 : {
1601 0 : err = stream_write_string (stream, data[i], data_n[i]);
1602 0 : if (err)
1603 0 : goto out;
1604 : }
1605 :
1606 : out:
1607 0 : for (i = 0; i < DIM(data); i++)
1608 0 : xfree (data[i]);
1609 0 : gcry_sexp_release (valuelist);
1610 0 : gcry_sexp_release (sublist);
1611 0 : mpint_list_free (mpis);
1612 0 : return err;
1613 : }
1614 :
1615 :
1616 : /* Signature encoder function for EdDSA. */
1617 : static gpg_error_t
1618 0 : ssh_signature_encoder_eddsa (ssh_key_type_spec_t *spec,
1619 : estream_t stream, gcry_sexp_t s_signature)
1620 : {
1621 0 : gpg_error_t err = 0;
1622 0 : gcry_sexp_t valuelist = NULL;
1623 0 : gcry_sexp_t sublist = NULL;
1624 : const char *elems;
1625 : size_t elems_n;
1626 : int i;
1627 :
1628 0 : unsigned char *data[2] = {NULL, NULL};
1629 : size_t data_n[2];
1630 0 : size_t totallen = 0;
1631 :
1632 0 : valuelist = gcry_sexp_nth (s_signature, 1);
1633 0 : if (!valuelist)
1634 : {
1635 0 : err = gpg_error (GPG_ERR_INV_SEXP);
1636 0 : goto out;
1637 : }
1638 :
1639 0 : elems = spec->elems_signature;
1640 0 : elems_n = strlen (elems);
1641 :
1642 0 : if (elems_n != DIM(data))
1643 : {
1644 0 : err = gpg_error (GPG_ERR_INV_SEXP);
1645 0 : goto out;
1646 : }
1647 :
1648 0 : for (i = 0; i < DIM(data); i++)
1649 : {
1650 0 : sublist = gcry_sexp_find_token (valuelist, spec->elems_signature + i, 1);
1651 0 : if (!sublist)
1652 : {
1653 0 : err = gpg_error (GPG_ERR_INV_SEXP);
1654 0 : break;
1655 : }
1656 :
1657 0 : data[i] = gcry_sexp_nth_buffer (sublist, 1, &data_n[i]);
1658 0 : if (!data[i])
1659 : {
1660 0 : err = gpg_error (GPG_ERR_INTERNAL); /* FIXME? */
1661 0 : break;
1662 : }
1663 0 : totallen += data_n[i];
1664 0 : gcry_sexp_release (sublist);
1665 0 : sublist = NULL;
1666 : }
1667 0 : if (err)
1668 0 : goto out;
1669 :
1670 0 : err = stream_write_uint32 (stream, totallen);
1671 0 : if (err)
1672 0 : goto out;
1673 :
1674 0 : for (i = 0; i < DIM(data); i++)
1675 : {
1676 0 : err = stream_write_data (stream, data[i], data_n[i]);
1677 0 : if (err)
1678 0 : goto out;
1679 : }
1680 :
1681 : out:
1682 0 : for (i = 0; i < DIM(data); i++)
1683 0 : xfree (data[i]);
1684 0 : gcry_sexp_release (valuelist);
1685 0 : gcry_sexp_release (sublist);
1686 0 : return err;
1687 : }
1688 :
1689 :
1690 : /*
1691 : S-Expressions.
1692 : */
1693 :
1694 :
1695 : /* This function constructs a new S-Expression for the key identified
1696 : by the KEY_SPEC, SECRET, CURVE_NAME, MPIS, and COMMENT, which is to
1697 : be stored at R_SEXP. Returns an error code. */
1698 : static gpg_error_t
1699 0 : sexp_key_construct (gcry_sexp_t *r_sexp,
1700 : ssh_key_type_spec_t key_spec, int secret,
1701 : const char *curve_name, gcry_mpi_t *mpis,
1702 : const char *comment)
1703 : {
1704 : gpg_error_t err;
1705 0 : gcry_sexp_t sexp_new = NULL;
1706 0 : void *formatbuf = NULL;
1707 0 : void **arg_list = NULL;
1708 0 : estream_t format = NULL;
1709 :
1710 :
1711 0 : if ((key_spec.flags & SPEC_FLAG_IS_EdDSA))
1712 : {
1713 : /* It is much easier and more readable to use a separate code
1714 : path for EdDSA. */
1715 0 : if (!curve_name)
1716 0 : err = gpg_error (GPG_ERR_INV_CURVE);
1717 0 : else if (!mpis[0] || !gcry_mpi_get_flag (mpis[0], GCRYMPI_FLAG_OPAQUE))
1718 0 : err = gpg_error (GPG_ERR_BAD_PUBKEY);
1719 0 : else if (secret
1720 0 : && (!mpis[1]
1721 0 : || !gcry_mpi_get_flag (mpis[1], GCRYMPI_FLAG_OPAQUE)))
1722 0 : err = gpg_error (GPG_ERR_BAD_SECKEY);
1723 0 : else if (secret)
1724 0 : err = gcry_sexp_build (&sexp_new, NULL,
1725 : "(private-key(ecc(curve %s)"
1726 : "(flags eddsa)(q %m)(d %m))"
1727 : "(comment%s))",
1728 : curve_name,
1729 0 : mpis[0], mpis[1],
1730 0 : comment? comment:"");
1731 : else
1732 0 : err = gcry_sexp_build (&sexp_new, NULL,
1733 : "(public-key(ecc(curve %s)"
1734 : "(flags eddsa)(q %m))"
1735 : "(comment%s))",
1736 : curve_name,
1737 : mpis[0],
1738 0 : comment? comment:"");
1739 : }
1740 : else
1741 : {
1742 0 : const char *key_identifier[] = { "public-key", "private-key" };
1743 : int arg_idx;
1744 : const char *elems;
1745 : size_t elems_n;
1746 : unsigned int i, j;
1747 :
1748 0 : if (secret)
1749 0 : elems = key_spec.elems_sexp_order;
1750 : else
1751 0 : elems = key_spec.elems_key_public;
1752 0 : elems_n = strlen (elems);
1753 :
1754 0 : format = es_fopenmem (0, "a+b");
1755 0 : if (!format)
1756 : {
1757 0 : err = gpg_error_from_syserror ();
1758 0 : goto out;
1759 : }
1760 :
1761 : /* Key identifier, algorithm identifier, mpis, comment, and a NULL
1762 : as a safeguard. */
1763 0 : arg_list = xtrymalloc (sizeof (*arg_list) * (2 + 1 + elems_n + 1 + 1));
1764 0 : if (!arg_list)
1765 : {
1766 0 : err = gpg_error_from_syserror ();
1767 0 : goto out;
1768 : }
1769 0 : arg_idx = 0;
1770 :
1771 0 : es_fputs ("(%s(%s", format);
1772 0 : arg_list[arg_idx++] = &key_identifier[secret];
1773 0 : arg_list[arg_idx++] = &key_spec.identifier;
1774 0 : if (curve_name)
1775 : {
1776 0 : es_fputs ("(curve%s)", format);
1777 0 : arg_list[arg_idx++] = &curve_name;
1778 : }
1779 :
1780 0 : for (i = 0; i < elems_n; i++)
1781 : {
1782 0 : es_fprintf (format, "(%c%%m)", elems[i]);
1783 0 : if (secret)
1784 : {
1785 0 : for (j = 0; j < elems_n; j++)
1786 0 : if (key_spec.elems_key_secret[j] == elems[i])
1787 0 : break;
1788 : }
1789 : else
1790 0 : j = i;
1791 0 : arg_list[arg_idx++] = &mpis[j];
1792 : }
1793 0 : es_fputs (")(comment%s))", format);
1794 0 : arg_list[arg_idx++] = &comment;
1795 0 : arg_list[arg_idx] = NULL;
1796 :
1797 0 : es_putc (0, format);
1798 0 : if (es_ferror (format))
1799 : {
1800 0 : err = gpg_error_from_syserror ();
1801 0 : goto out;
1802 : }
1803 0 : if (es_fclose_snatch (format, &formatbuf, NULL))
1804 : {
1805 0 : err = gpg_error_from_syserror ();
1806 0 : goto out;
1807 : }
1808 0 : format = NULL;
1809 :
1810 0 : err = gcry_sexp_build_array (&sexp_new, NULL, formatbuf, arg_list);
1811 : }
1812 :
1813 0 : if (!err)
1814 0 : *r_sexp = sexp_new;
1815 :
1816 : out:
1817 0 : es_fclose (format);
1818 0 : xfree (arg_list);
1819 0 : xfree (formatbuf);
1820 :
1821 0 : return err;
1822 : }
1823 :
1824 :
1825 : /* This function extracts the key from the s-expression SEXP according
1826 : to KEY_SPEC and stores it in ssh format at (R_BLOB, R_BLOBLEN). If
1827 : WITH_SECRET is true, the secret key parts are also extracted if
1828 : possible. Returns 0 on success or an error code. Note that data
1829 : stored at R_BLOB must be freed using es_free! */
1830 : static gpg_error_t
1831 0 : ssh_key_to_blob (gcry_sexp_t sexp, int with_secret,
1832 : ssh_key_type_spec_t key_spec,
1833 : void **r_blob, size_t *r_blob_size)
1834 : {
1835 0 : gpg_error_t err = 0;
1836 0 : gcry_sexp_t value_list = NULL;
1837 0 : gcry_sexp_t value_pair = NULL;
1838 0 : char *curve_name = NULL;
1839 0 : estream_t stream = NULL;
1840 0 : void *blob = NULL;
1841 : size_t blob_size;
1842 : const char *elems, *p_elems;
1843 : const char *data;
1844 : size_t datalen;
1845 :
1846 0 : *r_blob = NULL;
1847 0 : *r_blob_size = 0;
1848 :
1849 0 : stream = es_fopenmem (0, "r+b");
1850 0 : if (!stream)
1851 : {
1852 0 : err = gpg_error_from_syserror ();
1853 0 : goto out;
1854 : }
1855 :
1856 : /* Get the type of the key extpression. */
1857 0 : data = gcry_sexp_nth_data (sexp, 0, &datalen);
1858 0 : if (!data)
1859 : {
1860 0 : err = gpg_error (GPG_ERR_INV_SEXP);
1861 0 : goto out;
1862 : }
1863 :
1864 0 : if ((datalen == 10 && !strncmp (data, "public-key", 10))
1865 0 : || (datalen == 21 && !strncmp (data, "protected-private-key", 21))
1866 0 : || (datalen == 20 && !strncmp (data, "shadowed-private-key", 20)))
1867 0 : elems = key_spec.elems_key_public;
1868 0 : else if (datalen == 11 && !strncmp (data, "private-key", 11))
1869 0 : elems = with_secret? key_spec.elems_key_secret : key_spec.elems_key_public;
1870 : else
1871 : {
1872 0 : err = gpg_error (GPG_ERR_INV_SEXP);
1873 0 : goto out;
1874 : }
1875 :
1876 : /* Get the algorithm identifier. */
1877 0 : value_list = gcry_sexp_find_token (sexp, key_spec.identifier, 0);
1878 0 : if (!value_list)
1879 : {
1880 0 : err = gpg_error (GPG_ERR_INV_SEXP);
1881 0 : goto out;
1882 : }
1883 :
1884 : /* Write the ssh algorithm identifier. */
1885 0 : if ((key_spec.flags & SPEC_FLAG_IS_ECDSA))
1886 : {
1887 : /* Parse the "curve" parameter. We currently expect the curve
1888 : name for ECC and not the parameters of the curve. This can
1889 : easily be changed but then we need to find the curve name
1890 : from the parameters using gcry_pk_get_curve. */
1891 : const char *mapped;
1892 : const char *sshname;
1893 :
1894 0 : gcry_sexp_release (value_pair);
1895 0 : value_pair = gcry_sexp_find_token (value_list, "curve", 5);
1896 0 : if (!value_pair)
1897 : {
1898 0 : err = gpg_error (GPG_ERR_INV_CURVE);
1899 0 : goto out;
1900 : }
1901 0 : curve_name = gcry_sexp_nth_string (value_pair, 1);
1902 0 : if (!curve_name)
1903 : {
1904 0 : err = gpg_error (GPG_ERR_INV_CURVE); /* (Or out of core.) */
1905 0 : goto out;
1906 : }
1907 :
1908 : /* Fixme: The mapping should be done by using gcry_pk_get_curve
1909 : et al to iterate over all name aliases. */
1910 0 : if (!strcmp (curve_name, "NIST P-256"))
1911 0 : mapped = "nistp256";
1912 0 : else if (!strcmp (curve_name, "NIST P-384"))
1913 0 : mapped = "nistp384";
1914 0 : else if (!strcmp (curve_name, "NIST P-521"))
1915 0 : mapped = "nistp521";
1916 : else
1917 0 : mapped = NULL;
1918 0 : if (mapped)
1919 : {
1920 0 : xfree (curve_name);
1921 0 : curve_name = xtrystrdup (mapped);
1922 0 : if (!curve_name)
1923 : {
1924 0 : err = gpg_error_from_syserror ();
1925 0 : goto out;
1926 : }
1927 : }
1928 :
1929 0 : sshname = ssh_identifier_from_curve_name (curve_name);
1930 0 : if (!sshname)
1931 : {
1932 0 : err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
1933 0 : goto out;
1934 : }
1935 0 : err = stream_write_cstring (stream, sshname);
1936 0 : if (err)
1937 0 : goto out;
1938 0 : err = stream_write_cstring (stream, curve_name);
1939 0 : if (err)
1940 0 : goto out;
1941 : }
1942 : else
1943 : {
1944 : /* Note: This is also used for EdDSA. */
1945 0 : err = stream_write_cstring (stream, key_spec.ssh_identifier);
1946 0 : if (err)
1947 0 : goto out;
1948 : }
1949 :
1950 : /* Write the parameters. */
1951 0 : for (p_elems = elems; *p_elems; p_elems++)
1952 : {
1953 0 : gcry_sexp_release (value_pair);
1954 0 : value_pair = gcry_sexp_find_token (value_list, p_elems, 1);
1955 0 : if (!value_pair)
1956 : {
1957 0 : err = gpg_error (GPG_ERR_INV_SEXP);
1958 0 : goto out;
1959 : }
1960 0 : if ((key_spec.flags & SPEC_FLAG_IS_EdDSA))
1961 : {
1962 :
1963 0 : data = gcry_sexp_nth_data (value_pair, 1, &datalen);
1964 0 : if (!data)
1965 : {
1966 0 : err = gpg_error (GPG_ERR_INV_SEXP);
1967 0 : goto out;
1968 : }
1969 0 : if (*p_elems == 'q' && datalen)
1970 : { /* Remove the prefix 0x40. */
1971 0 : data++;
1972 0 : datalen--;
1973 : }
1974 0 : err = stream_write_string (stream, data, datalen);
1975 0 : if (err)
1976 0 : goto out;
1977 : }
1978 : else
1979 : {
1980 : gcry_mpi_t mpi;
1981 :
1982 : /* Note that we need to use STD format; i.e. prepend a 0x00
1983 : to indicate a positive number if the high bit is set. */
1984 0 : mpi = gcry_sexp_nth_mpi (value_pair, 1, GCRYMPI_FMT_STD);
1985 0 : if (!mpi)
1986 : {
1987 0 : err = gpg_error (GPG_ERR_INV_SEXP);
1988 0 : goto out;
1989 : }
1990 0 : err = stream_write_mpi (stream, mpi);
1991 0 : gcry_mpi_release (mpi);
1992 0 : if (err)
1993 0 : goto out;
1994 : }
1995 : }
1996 :
1997 0 : if (es_fclose_snatch (stream, &blob, &blob_size))
1998 : {
1999 0 : err = gpg_error_from_syserror ();
2000 0 : goto out;
2001 : }
2002 0 : stream = NULL;
2003 :
2004 0 : *r_blob = blob;
2005 0 : blob = NULL;
2006 0 : *r_blob_size = blob_size;
2007 :
2008 : out:
2009 0 : gcry_sexp_release (value_list);
2010 0 : gcry_sexp_release (value_pair);
2011 0 : xfree (curve_name);
2012 0 : es_fclose (stream);
2013 0 : es_free (blob);
2014 :
2015 0 : return err;
2016 : }
2017 :
2018 : /* Extract the car from SEXP, and create a newly created C-string
2019 : which is to be stored in IDENTIFIER. */
2020 : static gpg_error_t
2021 0 : sexp_extract_identifier (gcry_sexp_t sexp, char **identifier)
2022 : {
2023 : char *identifier_new;
2024 : gcry_sexp_t sublist;
2025 : const char *data;
2026 : size_t data_n;
2027 : gpg_error_t err;
2028 :
2029 0 : identifier_new = NULL;
2030 0 : err = 0;
2031 :
2032 0 : sublist = gcry_sexp_nth (sexp, 1);
2033 0 : if (! sublist)
2034 : {
2035 0 : err = gpg_error (GPG_ERR_INV_SEXP);
2036 0 : goto out;
2037 : }
2038 :
2039 0 : data = gcry_sexp_nth_data (sublist, 0, &data_n);
2040 0 : if (! data)
2041 : {
2042 0 : err = gpg_error (GPG_ERR_INV_SEXP);
2043 0 : goto out;
2044 : }
2045 :
2046 0 : identifier_new = make_cstring (data, data_n);
2047 0 : if (! identifier_new)
2048 : {
2049 0 : err = gpg_err_code_from_errno (errno);
2050 0 : goto out;
2051 : }
2052 :
2053 0 : *identifier = identifier_new;
2054 :
2055 : out:
2056 :
2057 0 : gcry_sexp_release (sublist);
2058 :
2059 0 : return err;
2060 : }
2061 :
2062 :
2063 :
2064 : /*
2065 :
2066 : Key I/O.
2067 :
2068 : */
2069 :
2070 : /* Search for a key specification entry. If SSH_NAME is not NULL,
2071 : search for an entry whose "ssh_name" is equal to SSH_NAME;
2072 : otherwise, search for an entry whose "name" is equal to NAME.
2073 : Store found entry in SPEC on success, return error otherwise. */
2074 : static gpg_error_t
2075 0 : ssh_key_type_lookup (const char *ssh_name, const char *name,
2076 : ssh_key_type_spec_t *spec)
2077 : {
2078 : gpg_error_t err;
2079 : unsigned int i;
2080 :
2081 : /* FIXME: Although this sees to work, it not be correct if the
2082 : lookup is done via name which might be "ecc" but actually it need
2083 : to check the flags to see whether it is eddsa or ecdsa. Maybe
2084 : the entire parameter controlled logic is too complicated and we
2085 : would do better by just switching on the ssh_name. */
2086 0 : for (i = 0; i < DIM (ssh_key_types); i++)
2087 0 : if ((ssh_name && (! strcmp (ssh_name, ssh_key_types[i].ssh_identifier)))
2088 0 : || (name && (! strcmp (name, ssh_key_types[i].identifier))))
2089 : break;
2090 :
2091 0 : if (i == DIM (ssh_key_types))
2092 0 : err = gpg_error (GPG_ERR_NOT_FOUND);
2093 : else
2094 : {
2095 0 : *spec = ssh_key_types[i];
2096 0 : err = 0;
2097 : }
2098 :
2099 0 : return err;
2100 : }
2101 :
2102 :
2103 : /* Receive a key from STREAM, according to the key specification given
2104 : as KEY_SPEC. Depending on SECRET, receive a secret or a public
2105 : key. If READ_COMMENT is true, receive a comment string as well.
2106 : Constructs a new S-Expression from received data and stores it in
2107 : KEY_NEW. Returns zero on success or an error code. */
2108 : static gpg_error_t
2109 0 : ssh_receive_key (estream_t stream, gcry_sexp_t *key_new, int secret,
2110 : int read_comment, ssh_key_type_spec_t *key_spec)
2111 : {
2112 : gpg_error_t err;
2113 0 : char *key_type = NULL;
2114 0 : char *comment = NULL;
2115 0 : gcry_sexp_t key = NULL;
2116 : ssh_key_type_spec_t spec;
2117 0 : gcry_mpi_t *mpi_list = NULL;
2118 : const char *elems;
2119 0 : char *curve_name = NULL;
2120 :
2121 :
2122 0 : err = stream_read_cstring (stream, &key_type);
2123 0 : if (err)
2124 0 : goto out;
2125 :
2126 0 : err = ssh_key_type_lookup (key_type, NULL, &spec);
2127 0 : if (err)
2128 0 : goto out;
2129 :
2130 0 : if ((spec.flags & SPEC_FLAG_IS_EdDSA))
2131 : {
2132 : /* The format of an EdDSA key is:
2133 : * string key_type ("ssh-ed25519")
2134 : * string public_key
2135 : * string private_key
2136 : *
2137 : * Note that the private key is the concatenation of the private
2138 : * key with the public key. Thus theres are 64 bytes; however
2139 : * we only want the real 32 byte private key - Libgcrypt expects
2140 : * this.
2141 : */
2142 0 : mpi_list = xtrycalloc (3, sizeof *mpi_list);
2143 0 : if (!mpi_list)
2144 : {
2145 0 : err = gpg_error_from_syserror ();
2146 0 : goto out;
2147 : }
2148 :
2149 0 : err = stream_read_blob (stream, 0, &mpi_list[0]);
2150 0 : if (err)
2151 0 : goto out;
2152 0 : if (secret)
2153 : {
2154 0 : u32 len = 0;
2155 : unsigned char *buffer;
2156 :
2157 : /* Read string length. */
2158 0 : err = stream_read_uint32 (stream, &len);
2159 0 : if (err)
2160 0 : goto out;
2161 0 : if (len != 32 && len != 64)
2162 : {
2163 0 : err = gpg_error (GPG_ERR_BAD_SECKEY);
2164 0 : goto out;
2165 : }
2166 0 : buffer = xtrymalloc_secure (32);
2167 0 : if (!buffer)
2168 : {
2169 0 : err = gpg_error_from_syserror ();
2170 0 : goto out;
2171 : }
2172 0 : err = stream_read_data (stream, buffer, 32);
2173 0 : if (err)
2174 : {
2175 0 : xfree (buffer);
2176 0 : goto out;
2177 : }
2178 0 : mpi_list[1] = gcry_mpi_set_opaque (NULL, buffer, 8*32);
2179 0 : buffer = NULL;
2180 0 : if (len == 64)
2181 : {
2182 0 : err = stream_read_skip (stream, 32);
2183 0 : if (err)
2184 0 : goto out;
2185 : }
2186 : }
2187 : }
2188 0 : else if ((spec.flags & SPEC_FLAG_IS_ECDSA))
2189 : {
2190 : /* The format of an ECDSA key is:
2191 : * string key_type ("ecdsa-sha2-nistp256" |
2192 : * "ecdsa-sha2-nistp384" |
2193 : * "ecdsa-sha2-nistp521" )
2194 : * string ecdsa_curve_name
2195 : * string ecdsa_public_key
2196 : * mpint ecdsa_private
2197 : *
2198 : * Note that we use the mpint reader instead of the string
2199 : * reader for ecsa_public_key.
2200 : */
2201 : unsigned char *buffer;
2202 : const char *mapped;
2203 :
2204 0 : err = stream_read_string (stream, 0, &buffer, NULL);
2205 0 : if (err)
2206 0 : goto out;
2207 0 : curve_name = buffer;
2208 : /* Fixme: Check that curve_name matches the keytype. */
2209 : /* Because Libgcrypt < 1.6 has no support for the "nistpNNN"
2210 : curve names, we need to translate them here to Libgcrypt's
2211 : native names. */
2212 0 : if (!strcmp (curve_name, "nistp256"))
2213 0 : mapped = "NIST P-256";
2214 0 : else if (!strcmp (curve_name, "nistp384"))
2215 0 : mapped = "NIST P-384";
2216 0 : else if (!strcmp (curve_name, "nistp521"))
2217 0 : mapped = "NIST P-521";
2218 : else
2219 0 : mapped = NULL;
2220 0 : if (mapped)
2221 : {
2222 0 : xfree (curve_name);
2223 0 : curve_name = xtrystrdup (mapped);
2224 0 : if (!curve_name)
2225 : {
2226 0 : err = gpg_error_from_syserror ();
2227 0 : goto out;
2228 : }
2229 : }
2230 :
2231 0 : err = ssh_receive_mpint_list (stream, secret, spec, &mpi_list);
2232 0 : if (err)
2233 0 : goto out;
2234 : }
2235 : else
2236 : {
2237 0 : err = ssh_receive_mpint_list (stream, secret, spec, &mpi_list);
2238 0 : if (err)
2239 0 : goto out;
2240 : }
2241 :
2242 0 : if (read_comment)
2243 : {
2244 0 : err = stream_read_cstring (stream, &comment);
2245 0 : if (err)
2246 0 : goto out;
2247 : }
2248 :
2249 0 : if (secret)
2250 0 : elems = spec.elems_key_secret;
2251 : else
2252 0 : elems = spec.elems_key_public;
2253 :
2254 0 : if (spec.key_modifier)
2255 : {
2256 0 : err = (*spec.key_modifier) (elems, mpi_list);
2257 0 : if (err)
2258 0 : goto out;
2259 : }
2260 :
2261 0 : if ((spec.flags & SPEC_FLAG_IS_EdDSA))
2262 : {
2263 0 : if (secret)
2264 : {
2265 0 : err = gcry_sexp_build (&key, NULL,
2266 : "(private-key(ecc(curve \"Ed25519\")"
2267 : "(flags eddsa)(q %m)(d %m))"
2268 : "(comment%s))",
2269 0 : mpi_list[0], mpi_list[1],
2270 0 : comment? comment:"");
2271 : }
2272 : else
2273 : {
2274 0 : err = gcry_sexp_build (&key, NULL,
2275 : "(public-key(ecc(curve \"Ed25519\")"
2276 : "(flags eddsa)(q %m))"
2277 : "(comment%s))",
2278 : mpi_list[0],
2279 0 : comment? comment:"");
2280 : }
2281 : }
2282 : else
2283 : {
2284 0 : err = sexp_key_construct (&key, spec, secret, curve_name, mpi_list,
2285 0 : comment? comment:"");
2286 0 : if (err)
2287 0 : goto out;
2288 : }
2289 :
2290 0 : if (key_spec)
2291 0 : *key_spec = spec;
2292 0 : *key_new = key;
2293 :
2294 : out:
2295 0 : mpint_list_free (mpi_list);
2296 0 : xfree (curve_name);
2297 0 : xfree (key_type);
2298 0 : xfree (comment);
2299 :
2300 0 : return err;
2301 : }
2302 :
2303 :
2304 : /* Write the public key from KEY to STREAM in SSH key format. If
2305 : OVERRIDE_COMMENT is not NULL, it will be used instead of the
2306 : comment stored in the key. */
2307 : static gpg_error_t
2308 0 : ssh_send_key_public (estream_t stream, gcry_sexp_t key,
2309 : const char *override_comment)
2310 : {
2311 : ssh_key_type_spec_t spec;
2312 0 : char *key_type = NULL;
2313 0 : char *comment = NULL;
2314 0 : void *blob = NULL;
2315 : size_t bloblen;
2316 : gpg_error_t err;
2317 :
2318 0 : err = sexp_extract_identifier (key, &key_type);
2319 0 : if (err)
2320 0 : goto out;
2321 :
2322 0 : err = ssh_key_type_lookup (NULL, key_type, &spec);
2323 0 : if (err)
2324 0 : goto out;
2325 :
2326 0 : err = ssh_key_to_blob (key, 0, spec, &blob, &bloblen);
2327 0 : if (err)
2328 0 : goto out;
2329 :
2330 0 : err = stream_write_string (stream, blob, bloblen);
2331 0 : if (err)
2332 0 : goto out;
2333 :
2334 0 : if (override_comment)
2335 0 : err = stream_write_cstring (stream, override_comment);
2336 : else
2337 : {
2338 0 : err = ssh_key_extract_comment (key, &comment);
2339 0 : if (err)
2340 0 : err = stream_write_cstring (stream, "(none)");
2341 : else
2342 0 : err = stream_write_cstring (stream, comment);
2343 : }
2344 0 : if (err)
2345 0 : goto out;
2346 :
2347 : out:
2348 0 : xfree (key_type);
2349 0 : xfree (comment);
2350 0 : es_free (blob);
2351 :
2352 0 : return err;
2353 : }
2354 :
2355 :
2356 : /* Read a public key out of BLOB/BLOB_SIZE according to the key
2357 : specification given as KEY_SPEC, storing the new key in KEY_PUBLIC.
2358 : Returns zero on success or an error code. */
2359 : static gpg_error_t
2360 0 : ssh_read_key_public_from_blob (unsigned char *blob, size_t blob_size,
2361 : gcry_sexp_t *key_public,
2362 : ssh_key_type_spec_t *key_spec)
2363 : {
2364 : gpg_error_t err;
2365 : estream_t blob_stream;
2366 :
2367 0 : blob_stream = es_fopenmem (0, "r+b");
2368 0 : if (!blob_stream)
2369 : {
2370 0 : err = gpg_error_from_syserror ();
2371 0 : goto out;
2372 : }
2373 :
2374 0 : err = stream_write_data (blob_stream, blob, blob_size);
2375 0 : if (err)
2376 0 : goto out;
2377 :
2378 0 : err = es_fseek (blob_stream, 0, SEEK_SET);
2379 0 : if (err)
2380 0 : goto out;
2381 :
2382 0 : err = ssh_receive_key (blob_stream, key_public, 0, 0, key_spec);
2383 :
2384 : out:
2385 0 : es_fclose (blob_stream);
2386 0 : return err;
2387 : }
2388 :
2389 :
2390 :
2391 : /* This function calculates the key grip for the key contained in the
2392 : S-Expression KEY and writes it to BUFFER, which must be large
2393 : enough to hold it. Returns usual error code. */
2394 : static gpg_error_t
2395 0 : ssh_key_grip (gcry_sexp_t key, unsigned char *buffer)
2396 : {
2397 0 : if (!gcry_pk_get_keygrip (key, buffer))
2398 : {
2399 0 : gpg_error_t err = gcry_pk_testkey (key);
2400 0 : return err? err : gpg_error (GPG_ERR_INTERNAL);
2401 : }
2402 :
2403 0 : return 0;
2404 : }
2405 :
2406 :
2407 : /* Check whether a smartcard is available and whether it has a usable
2408 : key. Store a copy of that key at R_PK and return 0. If no key is
2409 : available store NULL at R_PK and return an error code. If CARDSN
2410 : is not NULL, a string with the serial number of the card will be
2411 : a malloced and stored there. */
2412 : static gpg_error_t
2413 0 : card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn)
2414 : {
2415 : gpg_error_t err;
2416 : char *authkeyid;
2417 0 : char *serialno = NULL;
2418 : unsigned char *pkbuf;
2419 : size_t pkbuflen;
2420 : gcry_sexp_t s_pk;
2421 : unsigned char grip[20];
2422 :
2423 0 : *r_pk = NULL;
2424 0 : if (cardsn)
2425 0 : *cardsn = NULL;
2426 :
2427 : /* First see whether a card is available and whether the application
2428 : is supported. */
2429 0 : err = agent_card_getattr (ctrl, "$AUTHKEYID", &authkeyid);
2430 0 : if ( gpg_err_code (err) == GPG_ERR_CARD_REMOVED )
2431 : {
2432 : /* Ask for the serial number to reset the card. */
2433 0 : err = agent_card_serialno (ctrl, &serialno);
2434 0 : if (err)
2435 : {
2436 0 : if (opt.verbose)
2437 0 : log_info (_("error getting serial number of card: %s\n"),
2438 : gpg_strerror (err));
2439 0 : return err;
2440 : }
2441 0 : log_info (_("detected card with S/N: %s\n"), serialno);
2442 0 : err = agent_card_getattr (ctrl, "$AUTHKEYID", &authkeyid);
2443 : }
2444 0 : if (err)
2445 : {
2446 0 : log_error (_("no authentication key for ssh on card: %s\n"),
2447 : gpg_strerror (err));
2448 0 : xfree (serialno);
2449 0 : return err;
2450 : }
2451 :
2452 : /* Get the S/N if we don't have it yet. Use the fast getattr method. */
2453 0 : if (!serialno && (err = agent_card_getattr (ctrl, "SERIALNO", &serialno)) )
2454 : {
2455 0 : log_error (_("error getting serial number of card: %s\n"),
2456 : gpg_strerror (err));
2457 0 : xfree (authkeyid);
2458 0 : return err;
2459 : }
2460 :
2461 : /* Read the public key. */
2462 0 : err = agent_card_readkey (ctrl, authkeyid, &pkbuf);
2463 0 : if (err)
2464 : {
2465 0 : if (opt.verbose)
2466 0 : log_info (_("no suitable card key found: %s\n"), gpg_strerror (err));
2467 0 : xfree (serialno);
2468 0 : xfree (authkeyid);
2469 0 : return err;
2470 : }
2471 :
2472 0 : pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL);
2473 0 : err = gcry_sexp_sscan (&s_pk, NULL, (char*)pkbuf, pkbuflen);
2474 0 : if (err)
2475 : {
2476 0 : log_error ("failed to build S-Exp from received card key: %s\n",
2477 : gpg_strerror (err));
2478 0 : xfree (pkbuf);
2479 0 : xfree (serialno);
2480 0 : xfree (authkeyid);
2481 0 : return err;
2482 : }
2483 :
2484 0 : err = ssh_key_grip (s_pk, grip);
2485 0 : if (err)
2486 : {
2487 0 : log_debug ("error computing keygrip from received card key: %s\n",
2488 : gcry_strerror (err));
2489 0 : xfree (pkbuf);
2490 0 : gcry_sexp_release (s_pk);
2491 0 : xfree (serialno);
2492 0 : xfree (authkeyid);
2493 0 : return err;
2494 : }
2495 :
2496 0 : if ( agent_key_available (grip) )
2497 : {
2498 : /* (Shadow)-key is not available in our key storage. */
2499 : unsigned char *shadow_info;
2500 : unsigned char *tmp;
2501 :
2502 0 : shadow_info = make_shadow_info (serialno, authkeyid);
2503 0 : if (!shadow_info)
2504 : {
2505 0 : err = gpg_error_from_syserror ();
2506 0 : xfree (pkbuf);
2507 0 : gcry_sexp_release (s_pk);
2508 0 : xfree (serialno);
2509 0 : xfree (authkeyid);
2510 0 : return err;
2511 : }
2512 0 : err = agent_shadow_key (pkbuf, shadow_info, &tmp);
2513 0 : xfree (shadow_info);
2514 0 : if (err)
2515 : {
2516 0 : log_error (_("shadowing the key failed: %s\n"), gpg_strerror (err));
2517 0 : xfree (pkbuf);
2518 0 : gcry_sexp_release (s_pk);
2519 0 : xfree (serialno);
2520 0 : xfree (authkeyid);
2521 0 : return err;
2522 : }
2523 0 : xfree (pkbuf);
2524 0 : pkbuf = tmp;
2525 0 : pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL);
2526 0 : assert (pkbuflen);
2527 :
2528 0 : err = agent_write_private_key (grip, pkbuf, pkbuflen, 0);
2529 0 : if (err)
2530 : {
2531 0 : log_error (_("error writing key: %s\n"), gpg_strerror (err));
2532 0 : xfree (pkbuf);
2533 0 : gcry_sexp_release (s_pk);
2534 0 : xfree (serialno);
2535 0 : xfree (authkeyid);
2536 0 : return err;
2537 : }
2538 : }
2539 :
2540 0 : if (cardsn)
2541 : {
2542 : char *dispsn;
2543 :
2544 : /* If the card handler is able to return a short serialnumber,
2545 : use that one, else use the complete serialno. */
2546 0 : if (!agent_card_getattr (ctrl, "$DISPSERIALNO", &dispsn))
2547 : {
2548 0 : *cardsn = xtryasprintf ("cardno:%s", dispsn);
2549 0 : xfree (dispsn);
2550 : }
2551 : else
2552 0 : *cardsn = xtryasprintf ("cardno:%s", serialno);
2553 0 : if (!*cardsn)
2554 : {
2555 0 : err = gpg_error_from_syserror ();
2556 0 : xfree (pkbuf);
2557 0 : gcry_sexp_release (s_pk);
2558 0 : xfree (serialno);
2559 0 : xfree (authkeyid);
2560 0 : return err;
2561 : }
2562 : }
2563 :
2564 0 : xfree (pkbuf);
2565 0 : xfree (serialno);
2566 0 : xfree (authkeyid);
2567 0 : *r_pk = s_pk;
2568 0 : return 0;
2569 : }
2570 :
2571 :
2572 :
2573 :
2574 : /*
2575 :
2576 : Request handler. Each handler is provided with a CTRL context, a
2577 : REQUEST object and a RESPONSE object. The actual request is to be
2578 : read from REQUEST, the response needs to be written to RESPONSE.
2579 :
2580 : */
2581 :
2582 :
2583 : /* Handler for the "request_identities" command. */
2584 : static gpg_error_t
2585 0 : ssh_handler_request_identities (ctrl_t ctrl,
2586 : estream_t request, estream_t response)
2587 : {
2588 : ssh_key_type_spec_t spec;
2589 0 : char *key_fname = NULL;
2590 : char *fnameptr;
2591 : u32 key_counter;
2592 : estream_t key_blobs;
2593 : gcry_sexp_t key_secret;
2594 : gcry_sexp_t key_public;
2595 : gpg_error_t err;
2596 : int ret;
2597 0 : ssh_control_file_t cf = NULL;
2598 : char *cardsn;
2599 : gpg_error_t ret_err;
2600 :
2601 : (void)request;
2602 :
2603 : /* Prepare buffer stream. */
2604 :
2605 0 : key_secret = NULL;
2606 0 : key_public = NULL;
2607 0 : key_counter = 0;
2608 0 : err = 0;
2609 :
2610 0 : key_blobs = es_fopenmem (0, "r+b");
2611 0 : if (! key_blobs)
2612 : {
2613 0 : err = gpg_error_from_syserror ();
2614 0 : goto out;
2615 : }
2616 :
2617 : /* First check whether a key is currently available in the card
2618 : reader - this should be allowed even without being listed in
2619 : sshcontrol. */
2620 :
2621 0 : if (!opt.disable_scdaemon
2622 0 : && !card_key_available (ctrl, &key_public, &cardsn))
2623 : {
2624 0 : err = ssh_send_key_public (key_blobs, key_public, cardsn);
2625 0 : gcry_sexp_release (key_public);
2626 0 : key_public = NULL;
2627 0 : xfree (cardsn);
2628 0 : if (err)
2629 0 : goto out;
2630 :
2631 0 : key_counter++;
2632 : }
2633 :
2634 :
2635 : /* Prepare buffer for key name construction. */
2636 : {
2637 : char *dname;
2638 :
2639 0 : dname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, NULL);
2640 0 : if (!dname)
2641 : {
2642 0 : err = gpg_err_code_from_syserror ();
2643 0 : goto out;
2644 : }
2645 :
2646 0 : key_fname = xtrymalloc (strlen (dname) + 1 + 40 + 4 + 1);
2647 0 : if (!key_fname)
2648 : {
2649 0 : err = gpg_err_code_from_syserror ();
2650 0 : xfree (dname);
2651 0 : goto out;
2652 : }
2653 0 : fnameptr = stpcpy (stpcpy (key_fname, dname), "/");
2654 0 : xfree (dname);
2655 : }
2656 :
2657 : /* Then look at all the registered and non-disabled keys. */
2658 0 : err = open_control_file (&cf, 0);
2659 0 : if (err)
2660 0 : goto out;
2661 :
2662 0 : while (!read_control_file_item (cf))
2663 : {
2664 0 : if (!cf->item.valid)
2665 0 : continue; /* Should not happen. */
2666 0 : if (cf->item.disabled)
2667 0 : continue;
2668 0 : assert (strlen (cf->item.hexgrip) == 40);
2669 :
2670 0 : stpcpy (stpcpy (fnameptr, cf->item.hexgrip), ".key");
2671 :
2672 : /* Read file content. */
2673 : {
2674 : unsigned char *buffer;
2675 : size_t buffer_n;
2676 :
2677 0 : err = file_to_buffer (key_fname, &buffer, &buffer_n);
2678 0 : if (err)
2679 : {
2680 0 : log_error ("%s:%d: key '%s' skipped: %s\n",
2681 0 : cf->fname, cf->lnr, cf->item.hexgrip,
2682 : gpg_strerror (err));
2683 0 : continue;
2684 : }
2685 :
2686 0 : err = gcry_sexp_sscan (&key_secret, NULL, (char*)buffer, buffer_n);
2687 0 : xfree (buffer);
2688 0 : if (err)
2689 0 : goto out;
2690 : }
2691 :
2692 : {
2693 0 : char *key_type = NULL;
2694 :
2695 0 : err = sexp_extract_identifier (key_secret, &key_type);
2696 0 : if (err)
2697 0 : goto out;
2698 :
2699 0 : err = ssh_key_type_lookup (NULL, key_type, &spec);
2700 0 : xfree (key_type);
2701 0 : if (err)
2702 0 : goto out;
2703 : }
2704 :
2705 0 : err = ssh_send_key_public (key_blobs, key_secret, NULL);
2706 0 : if (err)
2707 0 : goto out;
2708 0 : gcry_sexp_release (key_secret);
2709 0 : key_secret = NULL;
2710 :
2711 0 : key_counter++;
2712 : }
2713 0 : err = 0;
2714 :
2715 0 : ret = es_fseek (key_blobs, 0, SEEK_SET);
2716 0 : if (ret)
2717 : {
2718 0 : err = gpg_error_from_syserror ();
2719 0 : goto out;
2720 : }
2721 :
2722 : out:
2723 : /* Send response. */
2724 :
2725 0 : gcry_sexp_release (key_secret);
2726 0 : gcry_sexp_release (key_public);
2727 :
2728 0 : if (!err)
2729 : {
2730 0 : ret_err = stream_write_byte (response, SSH_RESPONSE_IDENTITIES_ANSWER);
2731 0 : if (!ret_err)
2732 0 : ret_err = stream_write_uint32 (response, key_counter);
2733 0 : if (!ret_err)
2734 0 : ret_err = stream_copy (response, key_blobs);
2735 : }
2736 : else
2737 : {
2738 0 : ret_err = stream_write_byte (response, SSH_RESPONSE_FAILURE);
2739 : }
2740 :
2741 0 : es_fclose (key_blobs);
2742 0 : close_control_file (cf);
2743 0 : xfree (key_fname);
2744 :
2745 0 : return ret_err;
2746 : }
2747 :
2748 :
2749 : /* This function hashes the data contained in DATA of size DATA_N
2750 : according to the message digest algorithm specified by MD_ALGORITHM
2751 : and writes the message digest to HASH, which needs to large enough
2752 : for the digest. */
2753 : static gpg_error_t
2754 0 : data_hash (unsigned char *data, size_t data_n,
2755 : int md_algorithm, unsigned char *hash)
2756 : {
2757 0 : gcry_md_hash_buffer (md_algorithm, hash, data, data_n);
2758 :
2759 0 : return 0;
2760 : }
2761 :
2762 :
2763 : /* This function signs the data described by CTRL. If HASH is is not
2764 : NULL, (HASH,HASHLEN) overrides the hash stored in CTRL. This is to
2765 : allow the use of signature algorithms that implement the hashing
2766 : internally (e.g. Ed25519). On success the created signature is
2767 : stored in ssh format at R_SIG and it's size at R_SIGLEN; the caller
2768 : must use es_free to releaase this memory. */
2769 : static gpg_error_t
2770 0 : data_sign (ctrl_t ctrl, ssh_key_type_spec_t *spec,
2771 : const void *hash, size_t hashlen,
2772 : unsigned char **r_sig, size_t *r_siglen)
2773 : {
2774 : gpg_error_t err;
2775 0 : gcry_sexp_t signature_sexp = NULL;
2776 0 : estream_t stream = NULL;
2777 0 : void *blob = NULL;
2778 : size_t bloblen;
2779 : char hexgrip[40+1];
2780 :
2781 0 : *r_sig = NULL;
2782 0 : *r_siglen = 0;
2783 :
2784 : /* Quick check to see whether we have a valid keygrip and convert it
2785 : to hex. */
2786 0 : if (!ctrl->have_keygrip)
2787 : {
2788 0 : err = gpg_error (GPG_ERR_NO_SECKEY);
2789 0 : goto out;
2790 : }
2791 0 : bin2hex (ctrl->keygrip, 20, hexgrip);
2792 :
2793 : /* Ask for confirmation if needed. */
2794 0 : if (confirm_flag_from_sshcontrol (hexgrip))
2795 : {
2796 : gcry_sexp_t key;
2797 : char *fpr, *prompt;
2798 0 : char *comment = NULL;
2799 :
2800 0 : err = agent_raw_key_from_file (ctrl, ctrl->keygrip, &key);
2801 0 : if (err)
2802 0 : goto out;
2803 0 : err = ssh_get_fingerprint_string (key, &fpr);
2804 0 : if (!err)
2805 : {
2806 0 : gcry_sexp_t tmpsxp = gcry_sexp_find_token (key, "comment", 0);
2807 0 : if (tmpsxp)
2808 0 : comment = gcry_sexp_nth_string (tmpsxp, 1);
2809 0 : gcry_sexp_release (tmpsxp);
2810 : }
2811 0 : gcry_sexp_release (key);
2812 0 : if (err)
2813 0 : goto out;
2814 0 : prompt = xtryasprintf (L_("An ssh process requested the use of key%%0A"
2815 : " %s%%0A"
2816 : " (%s)%%0A"
2817 : "Do you want to allow this?"),
2818 : fpr, comment? comment:"");
2819 0 : xfree (fpr);
2820 0 : gcry_free (comment);
2821 0 : err = agent_get_confirmation (ctrl, prompt, L_("Allow"), L_("Deny"), 0);
2822 0 : xfree (prompt);
2823 0 : if (err)
2824 0 : goto out;
2825 : }
2826 :
2827 : /* Create signature. */
2828 0 : ctrl->use_auth_call = 1;
2829 0 : err = agent_pksign_do (ctrl, NULL,
2830 : L_("Please enter the passphrase "
2831 : "for the ssh key%%0A %F%%0A (%c)"),
2832 : &signature_sexp,
2833 : CACHE_MODE_SSH, ttl_from_sshcontrol,
2834 : hash, hashlen);
2835 0 : ctrl->use_auth_call = 0;
2836 0 : if (err)
2837 0 : goto out;
2838 :
2839 0 : stream = es_fopenmem (0, "r+b");
2840 0 : if (!stream)
2841 : {
2842 0 : err = gpg_error_from_syserror ();
2843 0 : goto out;
2844 : }
2845 :
2846 0 : err = stream_write_cstring (stream, spec->ssh_identifier);
2847 0 : if (err)
2848 0 : goto out;
2849 :
2850 0 : err = spec->signature_encoder (spec, stream, signature_sexp);
2851 0 : if (err)
2852 0 : goto out;
2853 :
2854 0 : err = es_fclose_snatch (stream, &blob, &bloblen);
2855 0 : if (err)
2856 0 : goto out;
2857 0 : stream = NULL;
2858 :
2859 0 : *r_sig = blob; blob = NULL;
2860 0 : *r_siglen = bloblen;
2861 :
2862 : out:
2863 0 : xfree (blob);
2864 0 : es_fclose (stream);
2865 0 : gcry_sexp_release (signature_sexp);
2866 :
2867 0 : return err;
2868 : }
2869 :
2870 :
2871 : /* Handler for the "sign_request" command. */
2872 : static gpg_error_t
2873 0 : ssh_handler_sign_request (ctrl_t ctrl, estream_t request, estream_t response)
2874 : {
2875 0 : gcry_sexp_t key = NULL;
2876 : ssh_key_type_spec_t spec;
2877 : unsigned char hash[MAX_DIGEST_LEN];
2878 : unsigned int hash_n;
2879 : unsigned char key_grip[20];
2880 0 : unsigned char *key_blob = NULL;
2881 : u32 key_blob_size;
2882 0 : unsigned char *data = NULL;
2883 0 : unsigned char *sig = NULL;
2884 : size_t sig_n;
2885 : u32 data_size;
2886 : u32 flags;
2887 : gpg_error_t err;
2888 : gpg_error_t ret_err;
2889 : int hash_algo;
2890 :
2891 : /* Receive key. */
2892 :
2893 0 : err = stream_read_string (request, 0, &key_blob, &key_blob_size);
2894 0 : if (err)
2895 0 : goto out;
2896 :
2897 0 : err = ssh_read_key_public_from_blob (key_blob, key_blob_size, &key, &spec);
2898 0 : if (err)
2899 0 : goto out;
2900 :
2901 : /* Receive data to sign. */
2902 0 : err = stream_read_string (request, 0, &data, &data_size);
2903 0 : if (err)
2904 0 : goto out;
2905 :
2906 : /* FIXME? */
2907 0 : err = stream_read_uint32 (request, &flags);
2908 0 : if (err)
2909 0 : goto out;
2910 :
2911 0 : hash_algo = spec.hash_algo;
2912 0 : if (!hash_algo)
2913 0 : hash_algo = GCRY_MD_SHA1; /* Use the default. */
2914 0 : ctrl->digest.algo = hash_algo;
2915 0 : if ((spec.flags & SPEC_FLAG_USE_PKCS1V2))
2916 0 : ctrl->digest.raw_value = 0;
2917 : else
2918 0 : ctrl->digest.raw_value = 1;
2919 :
2920 : /* Calculate key grip. */
2921 0 : err = ssh_key_grip (key, key_grip);
2922 0 : if (err)
2923 0 : goto out;
2924 0 : ctrl->have_keygrip = 1;
2925 0 : memcpy (ctrl->keygrip, key_grip, 20);
2926 :
2927 : /* Hash data unless we use EdDSA. */
2928 0 : if ((spec.flags & SPEC_FLAG_IS_EdDSA))
2929 : {
2930 0 : ctrl->digest.valuelen = 0;
2931 : }
2932 : else
2933 : {
2934 0 : hash_n = gcry_md_get_algo_dlen (hash_algo);
2935 0 : if (!hash_n)
2936 : {
2937 0 : err = gpg_error (GPG_ERR_INTERNAL);
2938 0 : goto out;
2939 : }
2940 0 : err = data_hash (data, data_size, hash_algo, hash);
2941 0 : if (err)
2942 0 : goto out;
2943 0 : memcpy (ctrl->digest.value, hash, hash_n);
2944 0 : ctrl->digest.valuelen = hash_n;
2945 : }
2946 :
2947 : /* Sign data. */
2948 0 : if ((spec.flags & SPEC_FLAG_IS_EdDSA))
2949 0 : err = data_sign (ctrl, &spec, data, data_size, &sig, &sig_n);
2950 : else
2951 0 : err = data_sign (ctrl, &spec, NULL, 0, &sig, &sig_n);
2952 :
2953 : out:
2954 : /* Done. */
2955 0 : if (!err)
2956 : {
2957 0 : ret_err = stream_write_byte (response, SSH_RESPONSE_SIGN_RESPONSE);
2958 0 : if (ret_err)
2959 0 : goto leave;
2960 0 : ret_err = stream_write_string (response, sig, sig_n);
2961 0 : if (ret_err)
2962 0 : goto leave;
2963 : }
2964 : else
2965 : {
2966 0 : log_error ("ssh sign request failed: %s <%s>\n",
2967 : gpg_strerror (err), gpg_strsource (err));
2968 0 : ret_err = stream_write_byte (response, SSH_RESPONSE_FAILURE);
2969 0 : if (ret_err)
2970 0 : goto leave;
2971 : }
2972 :
2973 : leave:
2974 :
2975 0 : gcry_sexp_release (key);
2976 0 : xfree (key_blob);
2977 0 : xfree (data);
2978 0 : es_free (sig);
2979 :
2980 0 : return ret_err;
2981 : }
2982 :
2983 :
2984 : /* This function extracts the comment contained in the key
2985 : s-expression KEY and stores a copy in COMMENT. Returns usual error
2986 : code. */
2987 : static gpg_error_t
2988 0 : ssh_key_extract_comment (gcry_sexp_t key, char **r_comment)
2989 : {
2990 : gcry_sexp_t comment_list;
2991 :
2992 0 : *r_comment = NULL;
2993 :
2994 0 : comment_list = gcry_sexp_find_token (key, "comment", 0);
2995 0 : if (!comment_list)
2996 0 : return gpg_error (GPG_ERR_INV_SEXP);
2997 :
2998 0 : *r_comment = gcry_sexp_nth_string (comment_list, 1);
2999 0 : gcry_sexp_release (comment_list);
3000 0 : if (!*r_comment)
3001 0 : return gpg_error (GPG_ERR_INV_SEXP);
3002 :
3003 0 : return 0;
3004 : }
3005 :
3006 :
3007 : /* This function converts the key contained in the S-Expression KEY
3008 : into a buffer, which is protected by the passphrase PASSPHRASE.
3009 : Returns usual error code. */
3010 : static gpg_error_t
3011 0 : ssh_key_to_protected_buffer (gcry_sexp_t key, const char *passphrase,
3012 : unsigned char **buffer, size_t *buffer_n)
3013 : {
3014 : unsigned char *buffer_new;
3015 : unsigned int buffer_new_n;
3016 : gpg_error_t err;
3017 :
3018 0 : err = 0;
3019 0 : buffer_new_n = gcry_sexp_sprint (key, GCRYSEXP_FMT_CANON, NULL, 0);
3020 0 : buffer_new = xtrymalloc_secure (buffer_new_n);
3021 0 : if (! buffer_new)
3022 : {
3023 0 : err = gpg_error_from_syserror ();
3024 0 : goto out;
3025 : }
3026 :
3027 0 : gcry_sexp_sprint (key, GCRYSEXP_FMT_CANON, buffer_new, buffer_new_n);
3028 : /* FIXME: guarantee? */
3029 :
3030 0 : err = agent_protect (buffer_new, passphrase, buffer, buffer_n, 0);
3031 :
3032 : out:
3033 :
3034 0 : xfree (buffer_new);
3035 :
3036 0 : return err;
3037 : }
3038 :
3039 :
3040 :
3041 : /* Callback function to compare the first entered PIN with the one
3042 : currently being entered. */
3043 : static gpg_error_t
3044 0 : reenter_compare_cb (struct pin_entry_info_s *pi)
3045 : {
3046 0 : const char *pin1 = pi->check_cb_arg;
3047 :
3048 0 : if (!strcmp (pin1, pi->pin))
3049 0 : return 0; /* okay */
3050 0 : return gpg_error (GPG_ERR_BAD_PASSPHRASE);
3051 : }
3052 :
3053 :
3054 : /* Store the ssh KEY into our local key storage and protect it after
3055 : asking for a passphrase. Cache that passphrase. TTL is the
3056 : maximum caching time for that key. If the key already exists in
3057 : our key storage, don't do anything. When entering a new key also
3058 : add an entry to the sshcontrol file. */
3059 : static gpg_error_t
3060 0 : ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
3061 : gcry_sexp_t key, int ttl, int confirm)
3062 : {
3063 : gpg_error_t err;
3064 : unsigned char key_grip_raw[20];
3065 : char key_grip[41];
3066 0 : unsigned char *buffer = NULL;
3067 : size_t buffer_n;
3068 0 : char *description = NULL;
3069 0 : const char *description2 = L_("Please re-enter this passphrase");
3070 0 : char *comment = NULL;
3071 0 : char *key_fpr = NULL;
3072 0 : const char *initial_errtext = NULL;
3073 0 : struct pin_entry_info_s *pi = NULL;
3074 0 : struct pin_entry_info_s *pi2 = NULL;
3075 :
3076 0 : err = ssh_key_grip (key, key_grip_raw);
3077 0 : if (err)
3078 0 : goto out;
3079 :
3080 : /* Check whether the key is already in our key storage. Don't do
3081 : anything then. */
3082 0 : if ( !agent_key_available (key_grip_raw) )
3083 0 : goto out; /* Yes, key is available. */
3084 :
3085 0 : err = ssh_get_fingerprint_string (key, &key_fpr);
3086 0 : if (err)
3087 0 : goto out;
3088 :
3089 0 : err = ssh_key_extract_comment (key, &comment);
3090 0 : if (err)
3091 0 : goto out;
3092 :
3093 0 : if ( asprintf (&description,
3094 : L_("Please enter a passphrase to protect"
3095 : " the received secret key%%0A"
3096 : " %s%%0A"
3097 : " %s%%0A"
3098 : "within gpg-agent's key storage"),
3099 0 : key_fpr, comment ? comment : "") < 0)
3100 : {
3101 0 : err = gpg_error_from_syserror ();
3102 0 : goto out;
3103 : }
3104 :
3105 0 : pi = gcry_calloc_secure (1, sizeof (*pi) + MAX_PASSPHRASE_LEN + 1);
3106 0 : if (!pi)
3107 : {
3108 0 : err = gpg_error_from_syserror ();
3109 0 : goto out;
3110 : }
3111 0 : pi2 = gcry_calloc_secure (1, sizeof (*pi2) + MAX_PASSPHRASE_LEN + 1);
3112 0 : if (!pi2)
3113 : {
3114 0 : err = gpg_error_from_syserror ();
3115 0 : goto out;
3116 : }
3117 0 : pi->max_length = MAX_PASSPHRASE_LEN + 1;
3118 0 : pi->max_tries = 1;
3119 0 : pi->with_repeat = 1;
3120 0 : pi2->max_length = MAX_PASSPHRASE_LEN + 1;
3121 0 : pi2->max_tries = 1;
3122 0 : pi2->check_cb = reenter_compare_cb;
3123 0 : pi2->check_cb_arg = pi->pin;
3124 :
3125 : next_try:
3126 0 : err = agent_askpin (ctrl, description, NULL, initial_errtext, pi, NULL, 0);
3127 0 : initial_errtext = NULL;
3128 0 : if (err)
3129 0 : goto out;
3130 :
3131 : /* Unless the passphrase is empty or the pinentry told us that
3132 : it already did the repetition check, ask to confirm it. */
3133 0 : if (*pi->pin && !pi->repeat_okay)
3134 : {
3135 0 : err = agent_askpin (ctrl, description2, NULL, NULL, pi2, NULL, 0);
3136 0 : if (gpg_err_code (err) == GPG_ERR_BAD_PASSPHRASE)
3137 : { /* The re-entered one did not match and the user did not
3138 : hit cancel. */
3139 0 : initial_errtext = L_("does not match - try again");
3140 0 : goto next_try;
3141 : }
3142 : }
3143 :
3144 0 : err = ssh_key_to_protected_buffer (key, pi->pin, &buffer, &buffer_n);
3145 0 : if (err)
3146 0 : goto out;
3147 :
3148 : /* Store this key to our key storage. */
3149 0 : err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0);
3150 0 : if (err)
3151 0 : goto out;
3152 :
3153 : /* Cache this passphrase. */
3154 0 : bin2hex (key_grip_raw, 20, key_grip);
3155 0 : err = agent_put_cache (key_grip, CACHE_MODE_SSH, pi->pin, ttl);
3156 0 : if (err)
3157 0 : goto out;
3158 :
3159 : /* And add an entry to the sshcontrol file. */
3160 0 : err = add_control_entry (ctrl, spec, key_grip, key_fpr, ttl, confirm);
3161 :
3162 :
3163 : out:
3164 0 : if (pi2 && pi2->max_length)
3165 0 : wipememory (pi2->pin, pi2->max_length);
3166 0 : xfree (pi2);
3167 0 : if (pi && pi->max_length)
3168 0 : wipememory (pi->pin, pi->max_length);
3169 0 : xfree (pi);
3170 0 : xfree (buffer);
3171 0 : xfree (comment);
3172 0 : xfree (key_fpr);
3173 0 : xfree (description);
3174 :
3175 0 : return err;
3176 : }
3177 :
3178 :
3179 : /* This function removes the key contained in the S-Expression KEY
3180 : from the local key storage, in case it exists there. Returns usual
3181 : error code. FIXME: this function is a stub. */
3182 : static gpg_error_t
3183 0 : ssh_identity_drop (gcry_sexp_t key)
3184 : {
3185 0 : unsigned char key_grip[21] = { 0 };
3186 : gpg_error_t err;
3187 :
3188 0 : err = ssh_key_grip (key, key_grip);
3189 0 : if (err)
3190 0 : goto out;
3191 :
3192 0 : key_grip[sizeof (key_grip) - 1] = 0;
3193 :
3194 : /* FIXME: What to do here - forgetting the passphrase or deleting
3195 : the key from key cache? */
3196 :
3197 : out:
3198 :
3199 0 : return err;
3200 : }
3201 :
3202 : /* Handler for the "add_identity" command. */
3203 : static gpg_error_t
3204 0 : ssh_handler_add_identity (ctrl_t ctrl, estream_t request, estream_t response)
3205 : {
3206 : gpg_error_t ret_err;
3207 : ssh_key_type_spec_t spec;
3208 : gpg_error_t err;
3209 : gcry_sexp_t key;
3210 : unsigned char b;
3211 : int confirm;
3212 : int ttl;
3213 :
3214 0 : confirm = 0;
3215 0 : key = NULL;
3216 0 : ttl = 0;
3217 :
3218 : /* FIXME? */
3219 0 : err = ssh_receive_key (request, &key, 1, 1, &spec);
3220 0 : if (err)
3221 0 : goto out;
3222 :
3223 : while (1)
3224 : {
3225 0 : err = stream_read_byte (request, &b);
3226 0 : if (gpg_err_code (err) == GPG_ERR_EOF)
3227 : {
3228 0 : err = 0;
3229 0 : break;
3230 : }
3231 :
3232 0 : switch (b)
3233 : {
3234 : case SSH_OPT_CONSTRAIN_LIFETIME:
3235 : {
3236 0 : u32 n = 0;
3237 :
3238 0 : err = stream_read_uint32 (request, &n);
3239 0 : if (! err)
3240 0 : ttl = n;
3241 0 : break;
3242 : }
3243 :
3244 : case SSH_OPT_CONSTRAIN_CONFIRM:
3245 : {
3246 0 : confirm = 1;
3247 0 : break;
3248 : }
3249 :
3250 : default:
3251 : /* FIXME: log/bad? */
3252 0 : break;
3253 : }
3254 0 : }
3255 0 : if (err)
3256 0 : goto out;
3257 :
3258 0 : err = ssh_identity_register (ctrl, &spec, key, ttl, confirm);
3259 :
3260 : out:
3261 :
3262 0 : gcry_sexp_release (key);
3263 :
3264 0 : if (! err)
3265 0 : ret_err = stream_write_byte (response, SSH_RESPONSE_SUCCESS);
3266 : else
3267 0 : ret_err = stream_write_byte (response, SSH_RESPONSE_FAILURE);
3268 :
3269 0 : return ret_err;
3270 : }
3271 :
3272 : /* Handler for the "remove_identity" command. */
3273 : static gpg_error_t
3274 0 : ssh_handler_remove_identity (ctrl_t ctrl,
3275 : estream_t request, estream_t response)
3276 : {
3277 : unsigned char *key_blob;
3278 : u32 key_blob_size;
3279 : gcry_sexp_t key;
3280 : gpg_error_t ret_err;
3281 : gpg_error_t err;
3282 :
3283 : (void)ctrl;
3284 :
3285 : /* Receive key. */
3286 :
3287 0 : key_blob = NULL;
3288 0 : key = NULL;
3289 :
3290 0 : err = stream_read_string (request, 0, &key_blob, &key_blob_size);
3291 0 : if (err)
3292 0 : goto out;
3293 :
3294 0 : err = ssh_read_key_public_from_blob (key_blob, key_blob_size, &key, NULL);
3295 0 : if (err)
3296 0 : goto out;
3297 :
3298 0 : err = ssh_identity_drop (key);
3299 :
3300 : out:
3301 :
3302 0 : xfree (key_blob);
3303 0 : gcry_sexp_release (key);
3304 :
3305 0 : if (! err)
3306 0 : ret_err = stream_write_byte (response, SSH_RESPONSE_SUCCESS);
3307 : else
3308 0 : ret_err = stream_write_byte (response, SSH_RESPONSE_FAILURE);
3309 :
3310 0 : return ret_err;
3311 : }
3312 :
3313 : /* FIXME: stub function. Actually useful? */
3314 : static gpg_error_t
3315 0 : ssh_identities_remove_all (void)
3316 : {
3317 : gpg_error_t err;
3318 :
3319 0 : err = 0;
3320 :
3321 : /* FIXME: shall we remove _all_ cache entries or only those
3322 : registered through the ssh emulation? */
3323 :
3324 0 : return err;
3325 : }
3326 :
3327 : /* Handler for the "remove_all_identities" command. */
3328 : static gpg_error_t
3329 0 : ssh_handler_remove_all_identities (ctrl_t ctrl,
3330 : estream_t request, estream_t response)
3331 : {
3332 : gpg_error_t ret_err;
3333 : gpg_error_t err;
3334 :
3335 : (void)ctrl;
3336 : (void)request;
3337 :
3338 0 : err = ssh_identities_remove_all ();
3339 :
3340 0 : if (! err)
3341 0 : ret_err = stream_write_byte (response, SSH_RESPONSE_SUCCESS);
3342 : else
3343 0 : ret_err = stream_write_byte (response, SSH_RESPONSE_FAILURE);
3344 :
3345 0 : return ret_err;
3346 : }
3347 :
3348 : /* Lock agent? FIXME: stub function. */
3349 : static gpg_error_t
3350 0 : ssh_lock (void)
3351 : {
3352 : gpg_error_t err;
3353 :
3354 : /* FIXME */
3355 0 : log_error ("ssh-agent's lock command is not implemented\n");
3356 0 : err = 0;
3357 :
3358 0 : return err;
3359 : }
3360 :
3361 : /* Unock agent? FIXME: stub function. */
3362 : static gpg_error_t
3363 0 : ssh_unlock (void)
3364 : {
3365 : gpg_error_t err;
3366 :
3367 0 : log_error ("ssh-agent's unlock command is not implemented\n");
3368 0 : err = 0;
3369 :
3370 0 : return err;
3371 : }
3372 :
3373 : /* Handler for the "lock" command. */
3374 : static gpg_error_t
3375 0 : ssh_handler_lock (ctrl_t ctrl, estream_t request, estream_t response)
3376 : {
3377 : gpg_error_t ret_err;
3378 : gpg_error_t err;
3379 :
3380 : (void)ctrl;
3381 : (void)request;
3382 :
3383 0 : err = ssh_lock ();
3384 :
3385 0 : if (! err)
3386 0 : ret_err = stream_write_byte (response, SSH_RESPONSE_SUCCESS);
3387 : else
3388 0 : ret_err = stream_write_byte (response, SSH_RESPONSE_FAILURE);
3389 :
3390 0 : return ret_err;
3391 : }
3392 :
3393 : /* Handler for the "unlock" command. */
3394 : static gpg_error_t
3395 0 : ssh_handler_unlock (ctrl_t ctrl, estream_t request, estream_t response)
3396 : {
3397 : gpg_error_t ret_err;
3398 : gpg_error_t err;
3399 :
3400 : (void)ctrl;
3401 : (void)request;
3402 :
3403 0 : err = ssh_unlock ();
3404 :
3405 0 : if (! err)
3406 0 : ret_err = stream_write_byte (response, SSH_RESPONSE_SUCCESS);
3407 : else
3408 0 : ret_err = stream_write_byte (response, SSH_RESPONSE_FAILURE);
3409 :
3410 0 : return ret_err;
3411 : }
3412 :
3413 :
3414 :
3415 : /* Return the request specification for the request identified by TYPE
3416 : or NULL in case the requested request specification could not be
3417 : found. */
3418 : static ssh_request_spec_t *
3419 0 : request_spec_lookup (int type)
3420 : {
3421 : ssh_request_spec_t *spec;
3422 : unsigned int i;
3423 :
3424 0 : for (i = 0; i < DIM (request_specs); i++)
3425 0 : if (request_specs[i].type == type)
3426 0 : break;
3427 0 : if (i == DIM (request_specs))
3428 : {
3429 0 : if (opt.verbose)
3430 0 : log_info ("ssh request %u is not supported\n", type);
3431 0 : spec = NULL;
3432 : }
3433 : else
3434 0 : spec = request_specs + i;
3435 :
3436 0 : return spec;
3437 : }
3438 :
3439 : /* Process a single request. The request is read from and the
3440 : response is written to STREAM_SOCK. Uses CTRL as context. Returns
3441 : zero in case of success, non zero in case of failure. */
3442 : static int
3443 0 : ssh_request_process (ctrl_t ctrl, estream_t stream_sock)
3444 : {
3445 : ssh_request_spec_t *spec;
3446 0 : estream_t response = NULL;
3447 0 : estream_t request = NULL;
3448 : unsigned char request_type;
3449 : gpg_error_t err;
3450 0 : int send_err = 0;
3451 : int ret;
3452 0 : unsigned char *request_data = NULL;
3453 : u32 request_data_size;
3454 : u32 response_size;
3455 :
3456 : /* Create memory streams for request/response data. The entire
3457 : request will be stored in secure memory, since it might contain
3458 : secret key material. The response does not have to be stored in
3459 : secure memory, since we never give out secret keys.
3460 :
3461 : Note: we only have little secure memory, but there is NO
3462 : possibility of DoS here; only trusted clients are allowed to
3463 : connect to the agent. What could happen is that the agent
3464 : returns out-of-secure-memory errors on requests in case the
3465 : agent's owner floods his own agent with many large messages.
3466 : -moritz */
3467 :
3468 : /* Retrieve request. */
3469 0 : err = stream_read_string (stream_sock, 1, &request_data, &request_data_size);
3470 0 : if (err)
3471 0 : goto out;
3472 :
3473 0 : if (opt.verbose > 1)
3474 0 : log_info ("received ssh request of length %u\n",
3475 : (unsigned int)request_data_size);
3476 :
3477 0 : if (! request_data_size)
3478 : {
3479 0 : send_err = 1;
3480 0 : goto out;
3481 : /* Broken request; FIXME. */
3482 : }
3483 :
3484 0 : request_type = request_data[0];
3485 0 : spec = request_spec_lookup (request_type);
3486 0 : if (! spec)
3487 : {
3488 0 : send_err = 1;
3489 0 : goto out;
3490 : /* Unknown request; FIXME. */
3491 : }
3492 :
3493 0 : if (spec->secret_input)
3494 0 : request = es_mopen (NULL, 0, 0, 1, realloc_secure, gcry_free, "r+b");
3495 : else
3496 0 : request = es_mopen (NULL, 0, 0, 1, gcry_realloc, gcry_free, "r+b");
3497 0 : if (! request)
3498 : {
3499 0 : err = gpg_error_from_syserror ();
3500 0 : goto out;
3501 : }
3502 0 : ret = es_setvbuf (request, NULL, _IONBF, 0);
3503 0 : if (ret)
3504 : {
3505 0 : err = gpg_error_from_syserror ();
3506 0 : goto out;
3507 : }
3508 0 : err = stream_write_data (request, request_data + 1, request_data_size - 1);
3509 0 : if (err)
3510 0 : goto out;
3511 0 : es_rewind (request);
3512 :
3513 0 : response = es_fopenmem (0, "r+b");
3514 0 : if (! response)
3515 : {
3516 0 : err = gpg_error_from_syserror ();
3517 0 : goto out;
3518 : }
3519 :
3520 0 : if (opt.verbose)
3521 0 : log_info ("ssh request handler for %s (%u) started\n",
3522 0 : spec->identifier, spec->type);
3523 :
3524 0 : err = (*spec->handler) (ctrl, request, response);
3525 :
3526 0 : if (opt.verbose)
3527 : {
3528 0 : if (err)
3529 0 : log_info ("ssh request handler for %s (%u) failed: %s\n",
3530 0 : spec->identifier, spec->type, gpg_strerror (err));
3531 : else
3532 0 : log_info ("ssh request handler for %s (%u) ready\n",
3533 0 : spec->identifier, spec->type);
3534 : }
3535 :
3536 0 : if (err)
3537 : {
3538 0 : send_err = 1;
3539 0 : goto out;
3540 : }
3541 :
3542 0 : response_size = es_ftell (response);
3543 0 : if (opt.verbose > 1)
3544 0 : log_info ("sending ssh response of length %u\n",
3545 : (unsigned int)response_size);
3546 :
3547 0 : err = es_fseek (response, 0, SEEK_SET);
3548 0 : if (err)
3549 : {
3550 0 : send_err = 1;
3551 0 : goto out;
3552 : }
3553 :
3554 0 : err = stream_write_uint32 (stream_sock, response_size);
3555 0 : if (err)
3556 : {
3557 0 : send_err = 1;
3558 0 : goto out;
3559 : }
3560 :
3561 0 : err = stream_copy (stream_sock, response);
3562 0 : if (err)
3563 0 : goto out;
3564 :
3565 0 : err = es_fflush (stream_sock);
3566 0 : if (err)
3567 0 : goto out;
3568 :
3569 : out:
3570 :
3571 0 : if (err && es_feof (stream_sock))
3572 0 : log_error ("error occured while processing request: %s\n",
3573 : gpg_strerror (err));
3574 :
3575 0 : if (send_err)
3576 : {
3577 0 : if (opt.verbose > 1)
3578 0 : log_info ("sending ssh error response\n");
3579 0 : err = stream_write_uint32 (stream_sock, 1);
3580 0 : if (err)
3581 0 : goto leave;
3582 0 : err = stream_write_byte (stream_sock, SSH_RESPONSE_FAILURE);
3583 0 : if (err)
3584 0 : goto leave;
3585 : }
3586 :
3587 : leave:
3588 :
3589 0 : es_fclose (request);
3590 0 : es_fclose (response);
3591 0 : xfree (request_data);
3592 :
3593 0 : return !!err;
3594 : }
3595 :
3596 :
3597 : /* Start serving client on SOCK_CLIENT. */
3598 : void
3599 0 : start_command_handler_ssh (ctrl_t ctrl, gnupg_fd_t sock_client)
3600 : {
3601 0 : estream_t stream_sock = NULL;
3602 : gpg_error_t err;
3603 : int ret;
3604 :
3605 0 : err = agent_copy_startup_env (ctrl);
3606 0 : if (err)
3607 0 : goto out;
3608 :
3609 : /* Create stream from socket. */
3610 0 : stream_sock = es_fdopen (FD2INT(sock_client), "r+");
3611 0 : if (!stream_sock)
3612 : {
3613 0 : err = gpg_error_from_syserror ();
3614 0 : log_error (_("failed to create stream from socket: %s\n"),
3615 : gpg_strerror (err));
3616 0 : goto out;
3617 : }
3618 : /* We have to disable the estream buffering, because the estream
3619 : core doesn't know about secure memory. */
3620 0 : ret = es_setvbuf (stream_sock, NULL, _IONBF, 0);
3621 0 : if (ret)
3622 : {
3623 0 : err = gpg_error_from_syserror ();
3624 0 : log_error ("failed to disable buffering "
3625 : "on socket stream: %s\n", gpg_strerror (err));
3626 0 : goto out;
3627 : }
3628 :
3629 : /* Main processing loop. */
3630 0 : while ( !ssh_request_process (ctrl, stream_sock) )
3631 : {
3632 : /* Check wether we have reached EOF before trying to read
3633 : another request. */
3634 : int c;
3635 :
3636 0 : c = es_fgetc (stream_sock);
3637 0 : if (c == EOF)
3638 0 : break;
3639 0 : es_ungetc (c, stream_sock);
3640 : }
3641 :
3642 : /* Reset the SCD in case it has been used. */
3643 0 : agent_reset_scd (ctrl);
3644 :
3645 :
3646 : out:
3647 0 : if (stream_sock)
3648 0 : es_fclose (stream_sock);
3649 0 : }
3650 :
3651 :
3652 : #ifdef HAVE_W32_SYSTEM
3653 : /* Serve one ssh-agent request. This is used for the Putty support.
3654 : REQUEST is the the mmapped memory which may be accessed up to a
3655 : length of MAXREQLEN. Returns 0 on success which also indicates
3656 : that a valid SSH response message is now in REQUEST. */
3657 : int
3658 : serve_mmapped_ssh_request (ctrl_t ctrl,
3659 : unsigned char *request, size_t maxreqlen)
3660 : {
3661 : gpg_error_t err;
3662 : int send_err = 0;
3663 : int valid_response = 0;
3664 : ssh_request_spec_t *spec;
3665 : u32 msglen;
3666 : estream_t request_stream, response_stream;
3667 :
3668 : if (agent_copy_startup_env (ctrl))
3669 : goto leave; /* Error setting up the environment. */
3670 :
3671 : if (maxreqlen < 5)
3672 : goto leave; /* Caller error. */
3673 :
3674 : msglen = uint32_construct (request[0], request[1], request[2], request[3]);
3675 : if (msglen < 1 || msglen > maxreqlen - 4)
3676 : {
3677 : log_error ("ssh message len (%u) out of range", (unsigned int)msglen);
3678 : goto leave;
3679 : }
3680 :
3681 : spec = request_spec_lookup (request[4]);
3682 : if (!spec)
3683 : {
3684 : send_err = 1; /* Unknown request type. */
3685 : goto leave;
3686 : }
3687 :
3688 : /* Create a stream object with the data part of the request. */
3689 : if (spec->secret_input)
3690 : request_stream = es_mopen (NULL, 0, 0, 1, realloc_secure, gcry_free, "r+");
3691 : else
3692 : request_stream = es_mopen (NULL, 0, 0, 1, gcry_realloc, gcry_free, "r+");
3693 : if (!request_stream)
3694 : {
3695 : err = gpg_error_from_syserror ();
3696 : goto leave;
3697 : }
3698 : /* We have to disable the estream buffering, because the estream
3699 : core doesn't know about secure memory. */
3700 : if (es_setvbuf (request_stream, NULL, _IONBF, 0))
3701 : {
3702 : err = gpg_error_from_syserror ();
3703 : goto leave;
3704 : }
3705 : /* Copy the request to the stream but omit the request type. */
3706 : err = stream_write_data (request_stream, request + 5, msglen - 1);
3707 : if (err)
3708 : goto leave;
3709 : es_rewind (request_stream);
3710 :
3711 : response_stream = es_fopenmem (0, "r+b");
3712 : if (!response_stream)
3713 : {
3714 : err = gpg_error_from_syserror ();
3715 : goto leave;
3716 : }
3717 :
3718 : if (opt.verbose)
3719 : log_info ("ssh request handler for %s (%u) started\n",
3720 : spec->identifier, spec->type);
3721 :
3722 : err = (*spec->handler) (ctrl, request_stream, response_stream);
3723 :
3724 : if (opt.verbose)
3725 : {
3726 : if (err)
3727 : log_info ("ssh request handler for %s (%u) failed: %s\n",
3728 : spec->identifier, spec->type, gpg_strerror (err));
3729 : else
3730 : log_info ("ssh request handler for %s (%u) ready\n",
3731 : spec->identifier, spec->type);
3732 : }
3733 :
3734 : es_fclose (request_stream);
3735 : request_stream = NULL;
3736 :
3737 : if (err)
3738 : {
3739 : send_err = 1;
3740 : goto leave;
3741 : }
3742 :
3743 : /* Put the response back into the mmapped buffer. */
3744 : {
3745 : void *response_data;
3746 : size_t response_size;
3747 :
3748 : /* NB: In contrast to the request-stream, the response stream
3749 : includes the the message type byte. */
3750 : if (es_fclose_snatch (response_stream, &response_data, &response_size))
3751 : {
3752 : log_error ("snatching ssh response failed: %s",
3753 : gpg_strerror (gpg_error_from_syserror ()));
3754 : send_err = 1; /* Ooops. */
3755 : goto leave;
3756 : }
3757 :
3758 : if (opt.verbose > 1)
3759 : log_info ("sending ssh response of length %u\n",
3760 : (unsigned int)response_size);
3761 : if (response_size > maxreqlen - 4)
3762 : {
3763 : log_error ("invalid length of the ssh response: %s",
3764 : gpg_strerror (GPG_ERR_INTERNAL));
3765 : es_free (response_data);
3766 : send_err = 1;
3767 : goto leave;
3768 : }
3769 :
3770 : request[0] = response_size >> 24;
3771 : request[1] = response_size >> 16;
3772 : request[2] = response_size >> 8;
3773 : request[3] = response_size >> 0;
3774 : memcpy (request+4, response_data, response_size);
3775 : es_free (response_data);
3776 : valid_response = 1;
3777 : }
3778 :
3779 : leave:
3780 : if (send_err)
3781 : {
3782 : request[0] = 0;
3783 : request[1] = 0;
3784 : request[2] = 0;
3785 : request[3] = 1;
3786 : request[4] = SSH_RESPONSE_FAILURE;
3787 : valid_response = 1;
3788 : }
3789 :
3790 : /* Reset the SCD in case it has been used. */
3791 : agent_reset_scd (ctrl);
3792 :
3793 : return valid_response? 0 : -1;
3794 : }
3795 : #endif /*HAVE_W32_SYSTEM*/
|