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