source: trunk/third/openssh/ssh-keygen.c @ 22570

Revision 22570, 34.0 KB checked in by ghudson, 18 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r22569, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3 * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 *                    All rights reserved
5 * Identity and host key generation and maintenance.
6 *
7 * As far as I am concerned, the code I have written for this software
8 * can be used freely for any purpose.  Any derived versions of this
9 * software must be clearly marked as such, and if the derived work is
10 * incompatible with the protocol description in the RFC file, it must be
11 * called by a name other than "ssh" or "Secure Shell".
12 */
13
14#include "includes.h"
15RCSID("$OpenBSD: ssh-keygen.c,v 1.128 2005/07/17 07:17:55 djm Exp $");
16
17#include <openssl/evp.h>
18#include <openssl/pem.h>
19
20#include "xmalloc.h"
21#include "key.h"
22#include "rsa.h"
23#include "authfile.h"
24#include "uuencode.h"
25#include "buffer.h"
26#include "bufaux.h"
27#include "pathnames.h"
28#include "log.h"
29#include "misc.h"
30#include "match.h"
31#include "hostfile.h"
32
33#ifdef SMARTCARD
34#include "scard.h"
35#endif
36#include "dns.h"
37
38/* Number of bits in the RSA/DSA key.  This value can be changed on the command line. */
39u_int32_t bits = 2048;
40
41/*
42 * Flag indicating that we just want to change the passphrase.  This can be
43 * set on the command line.
44 */
45int change_passphrase = 0;
46
47/*
48 * Flag indicating that we just want to change the comment.  This can be set
49 * on the command line.
50 */
51int change_comment = 0;
52
53int quiet = 0;
54
55/* Flag indicating that we want to hash a known_hosts file */
56int hash_hosts = 0;
57/* Flag indicating that we want lookup a host in known_hosts file */
58int find_host = 0;
59/* Flag indicating that we want to delete a host from a known_hosts file */
60int delete_host = 0;
61
62/* Flag indicating that we just want to see the key fingerprint */
63int print_fingerprint = 0;
64int print_bubblebabble = 0;
65
66/* The identity file name, given on the command line or entered by the user. */
67char identity_file[1024];
68int have_identity = 0;
69
70/* This is set to the passphrase if given on the command line. */
71char *identity_passphrase = NULL;
72
73/* This is set to the new passphrase if given on the command line. */
74char *identity_new_passphrase = NULL;
75
76/* This is set to the new comment if given on the command line. */
77char *identity_comment = NULL;
78
79/* Dump public key file in format used by real and the original SSH 2 */
80int convert_to_ssh2 = 0;
81int convert_from_ssh2 = 0;
82int print_public = 0;
83int print_generic = 0;
84
85char *key_type_name = NULL;
86
87/* argv0 */
88extern char *__progname;
89
90char hostname[MAXHOSTNAMELEN];
91
92/* moduli.c */
93int gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *);
94int prime_test(FILE *, FILE *, u_int32_t, u_int32_t);
95
96static void
97ask_filename(struct passwd *pw, const char *prompt)
98{
99        char buf[1024];
100        char *name = NULL;
101
102        if (key_type_name == NULL)
103                name = _PATH_SSH_CLIENT_ID_RSA;
104        else
105                switch (key_type_from_name(key_type_name)) {
106                case KEY_RSA1:
107                        name = _PATH_SSH_CLIENT_IDENTITY;
108                        break;
109                case KEY_DSA:
110                        name = _PATH_SSH_CLIENT_ID_DSA;
111                        break;
112                case KEY_RSA:
113                        name = _PATH_SSH_CLIENT_ID_RSA;
114                        break;
115                default:
116                        fprintf(stderr, "bad key type");
117                        exit(1);
118                        break;
119                }
120
121        snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name);
122        fprintf(stderr, "%s (%s): ", prompt, identity_file);
123        if (fgets(buf, sizeof(buf), stdin) == NULL)
124                exit(1);
125        if (strchr(buf, '\n'))
126                *strchr(buf, '\n') = 0;
127        if (strcmp(buf, "") != 0)
128                strlcpy(identity_file, buf, sizeof(identity_file));
129        have_identity = 1;
130}
131
132static Key *
133load_identity(char *filename)
134{
135        char *pass;
136        Key *prv;
137
138        prv = key_load_private(filename, "", NULL);
139        if (prv == NULL) {
140                if (identity_passphrase)
141                        pass = xstrdup(identity_passphrase);
142                else
143                        pass = read_passphrase("Enter passphrase: ",
144                            RP_ALLOW_STDIN);
145                prv = key_load_private(filename, pass, NULL);
146                memset(pass, 0, strlen(pass));
147                xfree(pass);
148        }
149        return prv;
150}
151
152#define SSH_COM_PUBLIC_BEGIN            "---- BEGIN SSH2 PUBLIC KEY ----"
153#define SSH_COM_PUBLIC_END              "---- END SSH2 PUBLIC KEY ----"
154#define SSH_COM_PRIVATE_BEGIN           "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
155#define SSH_COM_PRIVATE_KEY_MAGIC       0x3f6ff9eb
156
157static void
158do_convert_to_ssh2(struct passwd *pw)
159{
160        Key *k;
161        u_int len;
162        u_char *blob;
163        struct stat st;
164
165        if (!have_identity)
166                ask_filename(pw, "Enter file in which the key is");
167        if (stat(identity_file, &st) < 0) {
168                perror(identity_file);
169                exit(1);
170        }
171        if ((k = key_load_public(identity_file, NULL)) == NULL) {
172                if ((k = load_identity(identity_file)) == NULL) {
173                        fprintf(stderr, "load failed\n");
174                        exit(1);
175                }
176        }
177        if (k->type == KEY_RSA1) {
178                fprintf(stderr, "version 1 keys are not supported\n");
179                exit(1);
180        }
181        if (key_to_blob(k, &blob, &len) <= 0) {
182                fprintf(stderr, "key_to_blob failed\n");
183                exit(1);
184        }
185        fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
186        fprintf(stdout,
187            "Comment: \"%u-bit %s, converted from OpenSSH by %s@%s\"\n",
188            key_size(k), key_type(k),
189            pw->pw_name, hostname);
190        dump_base64(stdout, blob, len);
191        fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
192        key_free(k);
193        xfree(blob);
194        exit(0);
195}
196
197static void
198buffer_get_bignum_bits(Buffer *b, BIGNUM *value)
199{
200        u_int bignum_bits = buffer_get_int(b);
201        u_int bytes = (bignum_bits + 7) / 8;
202
203        if (buffer_len(b) < bytes)
204                fatal("buffer_get_bignum_bits: input buffer too small: "
205                    "need %d have %d", bytes, buffer_len(b));
206        BN_bin2bn(buffer_ptr(b), bytes, value);
207        buffer_consume(b, bytes);
208}
209
210static Key *
211do_convert_private_ssh2_from_blob(u_char *blob, u_int blen)
212{
213        Buffer b;
214        Key *key = NULL;
215        char *type, *cipher;
216        u_char *sig, data[] = "abcde12345";
217        int magic, rlen, ktype, i1, i2, i3, i4;
218        u_int slen;
219        u_long e;
220
221        buffer_init(&b);
222        buffer_append(&b, blob, blen);
223
224        magic  = buffer_get_int(&b);
225        if (magic != SSH_COM_PRIVATE_KEY_MAGIC) {
226                error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC);
227                buffer_free(&b);
228                return NULL;
229        }
230        i1 = buffer_get_int(&b);
231        type   = buffer_get_string(&b, NULL);
232        cipher = buffer_get_string(&b, NULL);
233        i2 = buffer_get_int(&b);
234        i3 = buffer_get_int(&b);
235        i4 = buffer_get_int(&b);
236        debug("ignore (%d %d %d %d)", i1,i2,i3,i4);
237        if (strcmp(cipher, "none") != 0) {
238                error("unsupported cipher %s", cipher);
239                xfree(cipher);
240                buffer_free(&b);
241                xfree(type);
242                return NULL;
243        }
244        xfree(cipher);
245
246        if (strstr(type, "dsa")) {
247                ktype = KEY_DSA;
248        } else if (strstr(type, "rsa")) {
249                ktype = KEY_RSA;
250        } else {
251                buffer_free(&b);
252                xfree(type);
253                return NULL;
254        }
255        key = key_new_private(ktype);
256        xfree(type);
257
258        switch (key->type) {
259        case KEY_DSA:
260                buffer_get_bignum_bits(&b, key->dsa->p);
261                buffer_get_bignum_bits(&b, key->dsa->g);
262                buffer_get_bignum_bits(&b, key->dsa->q);
263                buffer_get_bignum_bits(&b, key->dsa->pub_key);
264                buffer_get_bignum_bits(&b, key->dsa->priv_key);
265                break;
266        case KEY_RSA:
267                e  = buffer_get_char(&b);
268                debug("e %lx", e);
269                if (e < 30) {
270                        e <<= 8;
271                        e += buffer_get_char(&b);
272                        debug("e %lx", e);
273                        e <<= 8;
274                        e += buffer_get_char(&b);
275                        debug("e %lx", e);
276                }
277                if (!BN_set_word(key->rsa->e, e)) {
278                        buffer_free(&b);
279                        key_free(key);
280                        return NULL;
281                }
282                buffer_get_bignum_bits(&b, key->rsa->d);
283                buffer_get_bignum_bits(&b, key->rsa->n);
284                buffer_get_bignum_bits(&b, key->rsa->iqmp);
285                buffer_get_bignum_bits(&b, key->rsa->q);
286                buffer_get_bignum_bits(&b, key->rsa->p);
287                rsa_generate_additional_parameters(key->rsa);
288                break;
289        }
290        rlen = buffer_len(&b);
291        if (rlen != 0)
292                error("do_convert_private_ssh2_from_blob: "
293                    "remaining bytes in key blob %d", rlen);
294        buffer_free(&b);
295
296        /* try the key */
297        key_sign(key, &sig, &slen, data, sizeof(data));
298        key_verify(key, sig, slen, data, sizeof(data));
299        xfree(sig);
300        return key;
301}
302
303static void
304do_convert_from_ssh2(struct passwd *pw)
305{
306        Key *k;
307        int blen;
308        u_int len;
309        char line[1024], *p;
310        u_char blob[8096];
311        char encoded[8096];
312        struct stat st;
313        int escaped = 0, private = 0, ok;
314        FILE *fp;
315
316        if (!have_identity)
317                ask_filename(pw, "Enter file in which the key is");
318        if (stat(identity_file, &st) < 0) {
319                perror(identity_file);
320                exit(1);
321        }
322        fp = fopen(identity_file, "r");
323        if (fp == NULL) {
324                perror(identity_file);
325                exit(1);
326        }
327        encoded[0] = '\0';
328        while (fgets(line, sizeof(line), fp)) {
329                if (!(p = strchr(line, '\n'))) {
330                        fprintf(stderr, "input line too long.\n");
331                        exit(1);
332                }
333                if (p > line && p[-1] == '\\')
334                        escaped++;
335                if (strncmp(line, "----", 4) == 0 ||
336                    strstr(line, ": ") != NULL) {
337                        if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL)
338                                private = 1;
339                        if (strstr(line, " END ") != NULL) {
340                                break;
341                        }
342                        /* fprintf(stderr, "ignore: %s", line); */
343                        continue;
344                }
345                if (escaped) {
346                        escaped--;
347                        /* fprintf(stderr, "escaped: %s", line); */
348                        continue;
349                }
350                *p = '\0';
351                strlcat(encoded, line, sizeof(encoded));
352        }
353        len = strlen(encoded);
354        if (((len % 4) == 3) &&
355            (encoded[len-1] == '=') &&
356            (encoded[len-2] == '=') &&
357            (encoded[len-3] == '='))
358                encoded[len-3] = '\0';
359        blen = uudecode(encoded, blob, sizeof(blob));
360        if (blen < 0) {
361                fprintf(stderr, "uudecode failed.\n");
362                exit(1);
363        }
364        k = private ?
365            do_convert_private_ssh2_from_blob(blob, blen) :
366            key_from_blob(blob, blen);
367        if (k == NULL) {
368                fprintf(stderr, "decode blob failed.\n");
369                exit(1);
370        }
371        ok = private ?
372            (k->type == KEY_DSA ?
373                 PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) :
374                 PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) :
375            key_write(k, stdout);
376        if (!ok) {
377                fprintf(stderr, "key write failed");
378                exit(1);
379        }
380        key_free(k);
381        if (!private)
382                fprintf(stdout, "\n");
383        fclose(fp);
384        exit(0);
385}
386
387static void
388do_print_public(struct passwd *pw)
389{
390        Key *prv;
391        struct stat st;
392
393        if (!have_identity)
394                ask_filename(pw, "Enter file in which the key is");
395        if (stat(identity_file, &st) < 0) {
396                perror(identity_file);
397                exit(1);
398        }
399        prv = load_identity(identity_file);
400        if (prv == NULL) {
401                fprintf(stderr, "load failed\n");
402                exit(1);
403        }
404        if (!key_write(prv, stdout))
405                fprintf(stderr, "key_write failed");
406        key_free(prv);
407        fprintf(stdout, "\n");
408        exit(0);
409}
410
411#ifdef SMARTCARD
412static void
413do_upload(struct passwd *pw, const char *sc_reader_id)
414{
415        Key *prv = NULL;
416        struct stat st;
417        int ret;
418
419        if (!have_identity)
420                ask_filename(pw, "Enter file in which the key is");
421        if (stat(identity_file, &st) < 0) {
422                perror(identity_file);
423                exit(1);
424        }
425        prv = load_identity(identity_file);
426        if (prv == NULL) {
427                error("load failed");
428                exit(1);
429        }
430        ret = sc_put_key(prv, sc_reader_id);
431        key_free(prv);
432        if (ret < 0)
433                exit(1);
434        logit("loading key done");
435        exit(0);
436}
437
438static void
439do_download(struct passwd *pw, const char *sc_reader_id)
440{
441        Key **keys = NULL;
442        int i;
443
444        keys = sc_get_keys(sc_reader_id, NULL);
445        if (keys == NULL)
446                fatal("cannot read public key from smartcard");
447        for (i = 0; keys[i]; i++) {
448                key_write(keys[i], stdout);
449                key_free(keys[i]);
450                fprintf(stdout, "\n");
451        }
452        xfree(keys);
453        exit(0);
454}
455#endif /* SMARTCARD */
456
457static void
458do_fingerprint(struct passwd *pw)
459{
460        FILE *f;
461        Key *public;
462        char *comment = NULL, *cp, *ep, line[16*1024], *fp;
463        int i, skip = 0, num = 1, invalid = 1;
464        enum fp_rep rep;
465        enum fp_type fptype;
466        struct stat st;
467
468        fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
469        rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
470
471        if (!have_identity)
472                ask_filename(pw, "Enter file in which the key is");
473        if (stat(identity_file, &st) < 0) {
474                perror(identity_file);
475                exit(1);
476        }
477        public = key_load_public(identity_file, &comment);
478        if (public != NULL) {
479                fp = key_fingerprint(public, fptype, rep);
480                printf("%u %s %s\n", key_size(public), fp, comment);
481                key_free(public);
482                xfree(comment);
483                xfree(fp);
484                exit(0);
485        }
486        if (comment)
487                xfree(comment);
488
489        f = fopen(identity_file, "r");
490        if (f != NULL) {
491                while (fgets(line, sizeof(line), f)) {
492                        i = strlen(line) - 1;
493                        if (line[i] != '\n') {
494                                error("line %d too long: %.40s...", num, line);
495                                skip = 1;
496                                continue;
497                        }
498                        num++;
499                        if (skip) {
500                                skip = 0;
501                                continue;
502                        }
503                        line[i] = '\0';
504
505                        /* Skip leading whitespace, empty and comment lines. */
506                        for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
507                                ;
508                        if (!*cp || *cp == '\n' || *cp == '#')
509                                continue ;
510                        i = strtol(cp, &ep, 10);
511                        if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
512                                int quoted = 0;
513                                comment = cp;
514                                for (; *cp && (quoted || (*cp != ' ' &&
515                                    *cp != '\t')); cp++) {
516                                        if (*cp == '\\' && cp[1] == '"')
517                                                cp++;   /* Skip both */
518                                        else if (*cp == '"')
519                                                quoted = !quoted;
520                                }
521                                if (!*cp)
522                                        continue;
523                                *cp++ = '\0';
524                        }
525                        ep = cp;
526                        public = key_new(KEY_RSA1);
527                        if (key_read(public, &cp) != 1) {
528                                cp = ep;
529                                key_free(public);
530                                public = key_new(KEY_UNSPEC);
531                                if (key_read(public, &cp) != 1) {
532                                        key_free(public);
533                                        continue;
534                                }
535                        }
536                        comment = *cp ? cp : comment;
537                        fp = key_fingerprint(public, fptype, rep);
538                        printf("%u %s %s\n", key_size(public), fp,
539                            comment ? comment : "no comment");
540                        xfree(fp);
541                        key_free(public);
542                        invalid = 0;
543                }
544                fclose(f);
545        }
546        if (invalid) {
547                printf("%s is not a public key file.\n", identity_file);
548                exit(1);
549        }
550        exit(0);
551}
552
553static void
554print_host(FILE *f, char *name, Key *public, int hash)
555{
556        if (hash && (name = host_hash(name, NULL, 0)) == NULL)
557                fatal("hash_host failed");
558        fprintf(f, "%s ", name);
559        if (!key_write(public, f))
560                fatal("key_write failed");
561        fprintf(f, "\n");
562}
563
564static void
565do_known_hosts(struct passwd *pw, const char *name)
566{
567        FILE *in, *out = stdout;
568        Key *public;
569        char *cp, *cp2, *kp, *kp2;
570        char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN];
571        int c, i, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0;
572
573        if (!have_identity) {
574                cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
575                if (strlcpy(identity_file, cp, sizeof(identity_file)) >=
576                    sizeof(identity_file))
577                        fatal("Specified known hosts path too long");
578                xfree(cp);
579                have_identity = 1;
580        }
581        if ((in = fopen(identity_file, "r")) == NULL)
582                fatal("fopen: %s", strerror(errno));
583
584        /*
585         * Find hosts goes to stdout, hash and deletions happen in-place
586         * A corner case is ssh-keygen -HF foo, which should go to stdout
587         */
588        if (!find_host && (hash_hosts || delete_host)) {
589                if (strlcpy(tmp, identity_file, sizeof(tmp)) >= sizeof(tmp) ||
590                    strlcat(tmp, ".XXXXXXXXXX", sizeof(tmp)) >= sizeof(tmp) ||
591                    strlcpy(old, identity_file, sizeof(old)) >= sizeof(old) ||
592                    strlcat(old, ".old", sizeof(old)) >= sizeof(old))
593                        fatal("known_hosts path too long");
594                umask(077);
595                if ((c = mkstemp(tmp)) == -1)
596                        fatal("mkstemp: %s", strerror(errno));
597                if ((out = fdopen(c, "w")) == NULL) {
598                        c = errno;
599                        unlink(tmp);
600                        fatal("fdopen: %s", strerror(c));
601                }
602                inplace = 1;
603        }
604
605        while (fgets(line, sizeof(line), in)) {
606                num++;
607                i = strlen(line) - 1;
608                if (line[i] != '\n') {
609                        error("line %d too long: %.40s...", num, line);
610                        skip = 1;
611                        invalid = 1;
612                        continue;
613                }
614                if (skip) {
615                        skip = 0;
616                        continue;
617                }
618                line[i] = '\0';
619
620                /* Skip leading whitespace, empty and comment lines. */
621                for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
622                        ;
623                if (!*cp || *cp == '\n' || *cp == '#') {
624                        if (inplace)
625                                fprintf(out, "%s\n", cp);
626                        continue;
627                }
628                /* Find the end of the host name portion. */
629                for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++)
630                        ;
631                if (*kp == '\0' || *(kp + 1) == '\0') {
632                        error("line %d missing key: %.40s...",
633                            num, line);
634                        invalid = 1;
635                        continue;
636                }
637                *kp++ = '\0';
638                kp2 = kp;
639
640                public = key_new(KEY_RSA1);
641                if (key_read(public, &kp) != 1) {
642                        kp = kp2;
643                        key_free(public);
644                        public = key_new(KEY_UNSPEC);
645                        if (key_read(public, &kp) != 1) {
646                                error("line %d invalid key: %.40s...",
647                                    num, line);
648                                key_free(public);
649                                invalid = 1;
650                                continue;
651                        }
652                }
653
654                if (*cp == HASH_DELIM) {
655                        if (find_host || delete_host) {
656                                cp2 = host_hash(name, cp, strlen(cp));
657                                if (cp2 == NULL) {
658                                        error("line %d: invalid hashed "
659                                            "name: %.64s...", num, line);
660                                        invalid = 1;
661                                        continue;
662                                }
663                                c = (strcmp(cp2, cp) == 0);
664                                if (find_host && c) {
665                                        printf("# Host %s found: "
666                                            "line %d type %s\n", name,
667                                            num, key_type(public));
668                                        print_host(out, cp, public, 0);
669                                }
670                                if (delete_host && !c)
671                                        print_host(out, cp, public, 0);
672                        } else if (hash_hosts)
673                                print_host(out, cp, public, 0);
674                } else {
675                        if (find_host || delete_host) {
676                                c = (match_hostname(name, cp,
677                                    strlen(cp)) == 1);
678                                if (find_host && c) {
679                                        printf("# Host %s found: "
680                                            "line %d type %s\n", name,
681                                            num, key_type(public));
682                                        print_host(out, cp, public, hash_hosts);
683                                }
684                                if (delete_host && !c)
685                                        print_host(out, cp, public, 0);
686                        } else if (hash_hosts) {
687                                for (cp2 = strsep(&cp, ",");
688                                    cp2 != NULL && *cp2 != '\0';
689                                    cp2 = strsep(&cp, ",")) {
690                                        if (strcspn(cp2, "*?!") != strlen(cp2))
691                                                fprintf(stderr, "Warning: "
692                                                    "ignoring host name with "
693                                                    "metacharacters: %.64s\n",
694                                                    cp2);
695                                        else
696                                                print_host(out, cp2, public, 1);
697                                }
698                                has_unhashed = 1;
699                        }
700                }
701                key_free(public);
702        }
703        fclose(in);
704
705        if (invalid) {
706                fprintf(stderr, "%s is not a valid known_host file.\n",
707                    identity_file);
708                if (inplace) {
709                        fprintf(stderr, "Not replacing existing known_hosts "
710                            "file because of errors\n");
711                        fclose(out);
712                        unlink(tmp);
713                }
714                exit(1);
715        }
716
717        if (inplace) {
718                fclose(out);
719
720                /* Backup existing file */
721                if (unlink(old) == -1 && errno != ENOENT)
722                        fatal("unlink %.100s: %s", old, strerror(errno));
723                if (link(identity_file, old) == -1)
724                        fatal("link %.100s to %.100s: %s", identity_file, old,
725                            strerror(errno));
726                /* Move new one into place */
727                if (rename(tmp, identity_file) == -1) {
728                        error("rename\"%s\" to \"%s\": %s", tmp, identity_file,
729                            strerror(errno));
730                        unlink(tmp);
731                        unlink(old);
732                        exit(1);
733                }
734
735                fprintf(stderr, "%s updated.\n", identity_file);
736                fprintf(stderr, "Original contents retained as %s\n", old);
737                if (has_unhashed) {
738                        fprintf(stderr, "WARNING: %s contains unhashed "
739                            "entries\n", old);
740                        fprintf(stderr, "Delete this file to ensure privacy "
741                            "of hostnames\n");
742                }
743        }
744
745        exit(0);
746}
747
748/*
749 * Perform changing a passphrase.  The argument is the passwd structure
750 * for the current user.
751 */
752static void
753do_change_passphrase(struct passwd *pw)
754{
755        char *comment;
756        char *old_passphrase, *passphrase1, *passphrase2;
757        struct stat st;
758        Key *private;
759
760        if (!have_identity)
761                ask_filename(pw, "Enter file in which the key is");
762        if (stat(identity_file, &st) < 0) {
763                perror(identity_file);
764                exit(1);
765        }
766        /* Try to load the file with empty passphrase. */
767        private = key_load_private(identity_file, "", &comment);
768        if (private == NULL) {
769                if (identity_passphrase)
770                        old_passphrase = xstrdup(identity_passphrase);
771                else
772                        old_passphrase =
773                            read_passphrase("Enter old passphrase: ",
774                            RP_ALLOW_STDIN);
775                private = key_load_private(identity_file, old_passphrase,
776                    &comment);
777                memset(old_passphrase, 0, strlen(old_passphrase));
778                xfree(old_passphrase);
779                if (private == NULL) {
780                        printf("Bad passphrase.\n");
781                        exit(1);
782                }
783        }
784        printf("Key has comment '%s'\n", comment);
785
786        /* Ask the new passphrase (twice). */
787        if (identity_new_passphrase) {
788                passphrase1 = xstrdup(identity_new_passphrase);
789                passphrase2 = NULL;
790        } else {
791                passphrase1 =
792                        read_passphrase("Enter new passphrase (empty for no "
793                            "passphrase): ", RP_ALLOW_STDIN);
794                passphrase2 = read_passphrase("Enter same passphrase again: ",
795                    RP_ALLOW_STDIN);
796
797                /* Verify that they are the same. */
798                if (strcmp(passphrase1, passphrase2) != 0) {
799                        memset(passphrase1, 0, strlen(passphrase1));
800                        memset(passphrase2, 0, strlen(passphrase2));
801                        xfree(passphrase1);
802                        xfree(passphrase2);
803                        printf("Pass phrases do not match.  Try again.\n");
804                        exit(1);
805                }
806                /* Destroy the other copy. */
807                memset(passphrase2, 0, strlen(passphrase2));
808                xfree(passphrase2);
809        }
810
811        /* Save the file using the new passphrase. */
812        if (!key_save_private(private, identity_file, passphrase1, comment)) {
813                printf("Saving the key failed: %s.\n", identity_file);
814                memset(passphrase1, 0, strlen(passphrase1));
815                xfree(passphrase1);
816                key_free(private);
817                xfree(comment);
818                exit(1);
819        }
820        /* Destroy the passphrase and the copy of the key in memory. */
821        memset(passphrase1, 0, strlen(passphrase1));
822        xfree(passphrase1);
823        key_free(private);               /* Destroys contents */
824        xfree(comment);
825
826        printf("Your identification has been saved with the new passphrase.\n");
827        exit(0);
828}
829
830/*
831 * Print the SSHFP RR.
832 */
833static void
834do_print_resource_record(struct passwd *pw, char *hname)
835{
836        Key *public;
837        char *comment = NULL;
838        struct stat st;
839
840        if (!have_identity)
841                ask_filename(pw, "Enter file in which the key is");
842        if (stat(identity_file, &st) < 0) {
843                perror(identity_file);
844                exit(1);
845        }
846        public = key_load_public(identity_file, &comment);
847        if (public != NULL) {
848                export_dns_rr(hname, public, stdout, print_generic);
849                key_free(public);
850                xfree(comment);
851                exit(0);
852        }
853        if (comment)
854                xfree(comment);
855
856        printf("failed to read v2 public key from %s.\n", identity_file);
857        exit(1);
858}
859
860/*
861 * Change the comment of a private key file.
862 */
863static void
864do_change_comment(struct passwd *pw)
865{
866        char new_comment[1024], *comment, *passphrase;
867        Key *private;
868        Key *public;
869        struct stat st;
870        FILE *f;
871        int fd;
872
873        if (!have_identity)
874                ask_filename(pw, "Enter file in which the key is");
875        if (stat(identity_file, &st) < 0) {
876                perror(identity_file);
877                exit(1);
878        }
879        private = key_load_private(identity_file, "", &comment);
880        if (private == NULL) {
881                if (identity_passphrase)
882                        passphrase = xstrdup(identity_passphrase);
883                else if (identity_new_passphrase)
884                        passphrase = xstrdup(identity_new_passphrase);
885                else
886                        passphrase = read_passphrase("Enter passphrase: ",
887                            RP_ALLOW_STDIN);
888                /* Try to load using the passphrase. */
889                private = key_load_private(identity_file, passphrase, &comment);
890                if (private == NULL) {
891                        memset(passphrase, 0, strlen(passphrase));
892                        xfree(passphrase);
893                        printf("Bad passphrase.\n");
894                        exit(1);
895                }
896        } else {
897                passphrase = xstrdup("");
898        }
899        if (private->type != KEY_RSA1) {
900                fprintf(stderr, "Comments are only supported for RSA1 keys.\n");
901                key_free(private);
902                exit(1);
903        }
904        printf("Key now has comment '%s'\n", comment);
905
906        if (identity_comment) {
907                strlcpy(new_comment, identity_comment, sizeof(new_comment));
908        } else {
909                printf("Enter new comment: ");
910                fflush(stdout);
911                if (!fgets(new_comment, sizeof(new_comment), stdin)) {
912                        memset(passphrase, 0, strlen(passphrase));
913                        key_free(private);
914                        exit(1);
915                }
916                if (strchr(new_comment, '\n'))
917                        *strchr(new_comment, '\n') = 0;
918        }
919
920        /* Save the file using the new passphrase. */
921        if (!key_save_private(private, identity_file, passphrase, new_comment)) {
922                printf("Saving the key failed: %s.\n", identity_file);
923                memset(passphrase, 0, strlen(passphrase));
924                xfree(passphrase);
925                key_free(private);
926                xfree(comment);
927                exit(1);
928        }
929        memset(passphrase, 0, strlen(passphrase));
930        xfree(passphrase);
931        public = key_from_private(private);
932        key_free(private);
933
934        strlcat(identity_file, ".pub", sizeof(identity_file));
935        fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
936        if (fd == -1) {
937                printf("Could not save your public key in %s\n", identity_file);
938                exit(1);
939        }
940        f = fdopen(fd, "w");
941        if (f == NULL) {
942                printf("fdopen %s failed", identity_file);
943                exit(1);
944        }
945        if (!key_write(public, f))
946                fprintf(stderr, "write key failed");
947        key_free(public);
948        fprintf(f, " %s\n", new_comment);
949        fclose(f);
950
951        xfree(comment);
952
953        printf("The comment in your key file has been changed.\n");
954        exit(0);
955}
956
957static void
958usage(void)
959{
960        fprintf(stderr, "Usage: %s [options]\n", __progname);
961        fprintf(stderr, "Options:\n");
962        fprintf(stderr, "  -a trials   Number of trials for screening DH-GEX moduli.\n");
963        fprintf(stderr, "  -B          Show bubblebabble digest of key file.\n");
964        fprintf(stderr, "  -b bits     Number of bits in the key to create.\n");
965        fprintf(stderr, "  -C comment  Provide new comment.\n");
966        fprintf(stderr, "  -c          Change comment in private and public key files.\n");
967#ifdef SMARTCARD
968        fprintf(stderr, "  -D reader   Download public key from smartcard.\n");
969#endif /* SMARTCARD */
970        fprintf(stderr, "  -e          Convert OpenSSH to IETF SECSH key file.\n");
971        fprintf(stderr, "  -F hostname Find hostname in known hosts file.\n");
972        fprintf(stderr, "  -f filename Filename of the key file.\n");
973        fprintf(stderr, "  -G file     Generate candidates for DH-GEX moduli.\n");
974        fprintf(stderr, "  -g          Use generic DNS resource record format.\n");
975        fprintf(stderr, "  -H          Hash names in known_hosts file.\n");
976        fprintf(stderr, "  -i          Convert IETF SECSH to OpenSSH key file.\n");
977        fprintf(stderr, "  -l          Show fingerprint of key file.\n");
978        fprintf(stderr, "  -M memory   Amount of memory (MB) to use for generating DH-GEX moduli.\n");
979        fprintf(stderr, "  -N phrase   Provide new passphrase.\n");
980        fprintf(stderr, "  -P phrase   Provide old passphrase.\n");
981        fprintf(stderr, "  -p          Change passphrase of private key file.\n");
982        fprintf(stderr, "  -q          Quiet.\n");
983        fprintf(stderr, "  -R hostname Remove host from known_hosts file.\n");
984        fprintf(stderr, "  -r hostname Print DNS resource record.\n");
985        fprintf(stderr, "  -S start    Start point (hex) for generating DH-GEX moduli.\n");
986        fprintf(stderr, "  -T file     Screen candidates for DH-GEX moduli.\n");
987        fprintf(stderr, "  -t type     Specify type of key to create.\n");
988#ifdef SMARTCARD
989        fprintf(stderr, "  -U reader   Upload private key to smartcard.\n");
990#endif /* SMARTCARD */
991        fprintf(stderr, "  -v          Verbose.\n");
992        fprintf(stderr, "  -W gen      Generator to use for generating DH-GEX moduli.\n");
993        fprintf(stderr, "  -y          Read private key file and print public key.\n");
994
995        exit(1);
996}
997
998/*
999 * Main program for key management.
1000 */
1001int
1002main(int ac, char **av)
1003{
1004        char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2;
1005        char out_file[MAXPATHLEN], *reader_id = NULL;
1006        char *rr_hostname = NULL;
1007        Key *private, *public;
1008        struct passwd *pw;
1009        struct stat st;
1010        int opt, type, fd, download = 0;
1011        u_int32_t memory = 0, generator_wanted = 0, trials = 100;
1012        int do_gen_candidates = 0, do_screen_candidates = 0;
1013        int log_level = SYSLOG_LEVEL_INFO;
1014        BIGNUM *start = NULL;
1015        FILE *f;
1016        const char *errstr;
1017
1018        extern int optind;
1019        extern char *optarg;
1020
1021        __progname = ssh_get_progname(av[0]);
1022
1023        SSLeay_add_all_algorithms();
1024        log_init(av[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
1025
1026        init_rng();
1027        seed_rng();
1028
1029        /* we need this for the home * directory.  */
1030        pw = getpwuid(getuid());
1031        if (!pw) {
1032                printf("You don't exist, go away!\n");
1033                exit(1);
1034        }
1035        if (gethostname(hostname, sizeof(hostname)) < 0) {
1036                perror("gethostname");
1037                exit(1);
1038        }
1039
1040        while ((opt = getopt(ac, av,
1041            "degiqpclBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) {
1042                switch (opt) {
1043                case 'b':
1044                        bits = strtonum(optarg, 512, 32768, &errstr);
1045                        if (errstr)
1046                                fatal("Bits has bad value %s (%s)",
1047                                        optarg, errstr);
1048                        break;
1049                case 'F':
1050                        find_host = 1;
1051                        rr_hostname = optarg;
1052                        break;
1053                case 'H':
1054                        hash_hosts = 1;
1055                        break;
1056                case 'R':
1057                        delete_host = 1;
1058                        rr_hostname = optarg;
1059                        break;
1060                case 'l':
1061                        print_fingerprint = 1;
1062                        break;
1063                case 'B':
1064                        print_bubblebabble = 1;
1065                        break;
1066                case 'p':
1067                        change_passphrase = 1;
1068                        break;
1069                case 'c':
1070                        change_comment = 1;
1071                        break;
1072                case 'f':
1073                        if (strlcpy(identity_file, optarg, sizeof(identity_file)) >=
1074                            sizeof(identity_file))
1075                                fatal("Identity filename too long");
1076                        have_identity = 1;
1077                        break;
1078                case 'g':
1079                        print_generic = 1;
1080                        break;
1081                case 'P':
1082                        identity_passphrase = optarg;
1083                        break;
1084                case 'N':
1085                        identity_new_passphrase = optarg;
1086                        break;
1087                case 'C':
1088                        identity_comment = optarg;
1089                        break;
1090                case 'q':
1091                        quiet = 1;
1092                        break;
1093                case 'e':
1094                case 'x':
1095                        /* export key */
1096                        convert_to_ssh2 = 1;
1097                        break;
1098                case 'i':
1099                case 'X':
1100                        /* import key */
1101                        convert_from_ssh2 = 1;
1102                        break;
1103                case 'y':
1104                        print_public = 1;
1105                        break;
1106                case 'd':
1107                        key_type_name = "dsa";
1108                        break;
1109                case 't':
1110                        key_type_name = optarg;
1111                        break;
1112                case 'D':
1113                        download = 1;
1114                case 'U':
1115                        reader_id = optarg;
1116                        break;
1117                case 'v':
1118                        if (log_level == SYSLOG_LEVEL_INFO)
1119                                log_level = SYSLOG_LEVEL_DEBUG1;
1120                        else {
1121                                if (log_level >= SYSLOG_LEVEL_DEBUG1 &&
1122                                    log_level < SYSLOG_LEVEL_DEBUG3)
1123                                        log_level++;
1124                        }
1125                        break;
1126                case 'r':
1127                        rr_hostname = optarg;
1128                        break;
1129                case 'W':
1130                        generator_wanted = strtonum(optarg, 1, UINT_MAX, &errstr);
1131                        if (errstr)
1132                                fatal("Desired generator has bad value: %s (%s)",
1133                                        optarg, errstr);
1134                        break;
1135                case 'a':
1136                        trials = strtonum(optarg, 1, UINT_MAX, &errstr);
1137                        if (errstr)
1138                                fatal("Invalid number of trials: %s (%s)",
1139                                        optarg, errstr);
1140                        break;
1141                case 'M':
1142                        memory = strtonum(optarg, 1, UINT_MAX, &errstr);
1143                        if (errstr) {
1144                                fatal("Memory limit is %s: %s", errstr, optarg);
1145                        }
1146                        break;
1147                case 'G':
1148                        do_gen_candidates = 1;
1149                        if (strlcpy(out_file, optarg, sizeof(out_file)) >=
1150                            sizeof(out_file))
1151                                fatal("Output filename too long");
1152                        break;
1153                case 'T':
1154                        do_screen_candidates = 1;
1155                        if (strlcpy(out_file, optarg, sizeof(out_file)) >=
1156                            sizeof(out_file))
1157                                fatal("Output filename too long");
1158                        break;
1159                case 'S':
1160                        /* XXX - also compare length against bits */
1161                        if (BN_hex2bn(&start, optarg) == 0)
1162                                fatal("Invalid start point.");
1163                        break;
1164                case '?':
1165                default:
1166                        usage();
1167                }
1168        }
1169
1170        /* reinit */
1171        log_init(av[0], log_level, SYSLOG_FACILITY_USER, 1);
1172
1173        if (optind < ac) {
1174                printf("Too many arguments.\n");
1175                usage();
1176        }
1177        if (change_passphrase && change_comment) {
1178                printf("Can only have one of -p and -c.\n");
1179                usage();
1180        }
1181        if (delete_host || hash_hosts || find_host)
1182                do_known_hosts(pw, rr_hostname);
1183        if (print_fingerprint || print_bubblebabble)
1184                do_fingerprint(pw);
1185        if (change_passphrase)
1186                do_change_passphrase(pw);
1187        if (change_comment)
1188                do_change_comment(pw);
1189        if (convert_to_ssh2)
1190                do_convert_to_ssh2(pw);
1191        if (convert_from_ssh2)
1192                do_convert_from_ssh2(pw);
1193        if (print_public)
1194                do_print_public(pw);
1195        if (rr_hostname != NULL) {
1196                do_print_resource_record(pw, rr_hostname);
1197        }
1198        if (reader_id != NULL) {
1199#ifdef SMARTCARD
1200                if (download)
1201                        do_download(pw, reader_id);
1202                else
1203                        do_upload(pw, reader_id);
1204#else /* SMARTCARD */
1205                fatal("no support for smartcards.");
1206#endif /* SMARTCARD */
1207        }
1208
1209        if (do_gen_candidates) {
1210                FILE *out = fopen(out_file, "w");
1211
1212                if (out == NULL) {
1213                        error("Couldn't open modulus candidate file \"%s\": %s",
1214                            out_file, strerror(errno));
1215                        return (1);
1216                }
1217                if (gen_candidates(out, memory, bits, start) != 0)
1218                        fatal("modulus candidate generation failed\n");
1219
1220                return (0);
1221        }
1222
1223        if (do_screen_candidates) {
1224                FILE *in;
1225                FILE *out = fopen(out_file, "w");
1226
1227                if (have_identity && strcmp(identity_file, "-") != 0) {
1228                        if ((in = fopen(identity_file, "r")) == NULL) {
1229                                fatal("Couldn't open modulus candidate "
1230                                    "file \"%s\": %s", identity_file,
1231                                    strerror(errno));
1232                        }
1233                } else
1234                        in = stdin;
1235
1236                if (out == NULL) {
1237                        fatal("Couldn't open moduli file \"%s\": %s",
1238                            out_file, strerror(errno));
1239                }
1240                if (prime_test(in, out, trials, generator_wanted) != 0)
1241                        fatal("modulus screening failed\n");
1242                return (0);
1243        }
1244
1245        arc4random_stir();
1246
1247        if (key_type_name == NULL) {
1248                printf("You must specify a key type (-t).\n");
1249                usage();
1250        }
1251        type = key_type_from_name(key_type_name);
1252        if (type == KEY_UNSPEC) {
1253                fprintf(stderr, "unknown key type %s\n", key_type_name);
1254                exit(1);
1255        }
1256        if (!quiet)
1257                printf("Generating public/private %s key pair.\n", key_type_name);
1258        private = key_generate(type, bits);
1259        if (private == NULL) {
1260                fprintf(stderr, "key_generate failed");
1261                exit(1);
1262        }
1263        public  = key_from_private(private);
1264
1265        if (!have_identity)
1266                ask_filename(pw, "Enter file in which to save the key");
1267
1268        /* Create ~/.ssh directory if it doesn\'t already exist. */
1269        snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR);
1270        if (strstr(identity_file, dotsshdir) != NULL &&
1271            stat(dotsshdir, &st) < 0) {
1272                if (mkdir(dotsshdir, 0700) < 0)
1273                        error("Could not create directory '%s'.", dotsshdir);
1274                else if (!quiet)
1275                        printf("Created directory '%s'.\n", dotsshdir);
1276        }
1277        /* If the file already exists, ask the user to confirm. */
1278        if (stat(identity_file, &st) >= 0) {
1279                char yesno[3];
1280                printf("%s already exists.\n", identity_file);
1281                printf("Overwrite (y/n)? ");
1282                fflush(stdout);
1283                if (fgets(yesno, sizeof(yesno), stdin) == NULL)
1284                        exit(1);
1285                if (yesno[0] != 'y' && yesno[0] != 'Y')
1286                        exit(1);
1287        }
1288        /* Ask for a passphrase (twice). */
1289        if (identity_passphrase)
1290                passphrase1 = xstrdup(identity_passphrase);
1291        else if (identity_new_passphrase)
1292                passphrase1 = xstrdup(identity_new_passphrase);
1293        else {
1294passphrase_again:
1295                passphrase1 =
1296                        read_passphrase("Enter passphrase (empty for no "
1297                            "passphrase): ", RP_ALLOW_STDIN);
1298                passphrase2 = read_passphrase("Enter same passphrase again: ",
1299                    RP_ALLOW_STDIN);
1300                if (strcmp(passphrase1, passphrase2) != 0) {
1301                        /*
1302                         * The passphrases do not match.  Clear them and
1303                         * retry.
1304                         */
1305                        memset(passphrase1, 0, strlen(passphrase1));
1306                        memset(passphrase2, 0, strlen(passphrase2));
1307                        xfree(passphrase1);
1308                        xfree(passphrase2);
1309                        printf("Passphrases do not match.  Try again.\n");
1310                        goto passphrase_again;
1311                }
1312                /* Clear the other copy of the passphrase. */
1313                memset(passphrase2, 0, strlen(passphrase2));
1314                xfree(passphrase2);
1315        }
1316
1317        if (identity_comment) {
1318                strlcpy(comment, identity_comment, sizeof(comment));
1319        } else {
1320                /* Create default commend field for the passphrase. */
1321                snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
1322        }
1323
1324        /* Save the key with the given passphrase and comment. */
1325        if (!key_save_private(private, identity_file, passphrase1, comment)) {
1326                printf("Saving the key failed: %s.\n", identity_file);
1327                memset(passphrase1, 0, strlen(passphrase1));
1328                xfree(passphrase1);
1329                exit(1);
1330        }
1331        /* Clear the passphrase. */
1332        memset(passphrase1, 0, strlen(passphrase1));
1333        xfree(passphrase1);
1334
1335        /* Clear the private key and the random number generator. */
1336        key_free(private);
1337        arc4random_stir();
1338
1339        if (!quiet)
1340                printf("Your identification has been saved in %s.\n", identity_file);
1341
1342        strlcat(identity_file, ".pub", sizeof(identity_file));
1343        fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1344        if (fd == -1) {
1345                printf("Could not save your public key in %s\n", identity_file);
1346                exit(1);
1347        }
1348        f = fdopen(fd, "w");
1349        if (f == NULL) {
1350                printf("fdopen %s failed", identity_file);
1351                exit(1);
1352        }
1353        if (!key_write(public, f))
1354                fprintf(stderr, "write key failed");
1355        fprintf(f, " %s\n", comment);
1356        fclose(f);
1357
1358        if (!quiet) {
1359                char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
1360                printf("Your public key has been saved in %s.\n",
1361                    identity_file);
1362                printf("The key fingerprint is:\n");
1363                printf("%s %s\n", fp, comment);
1364                xfree(fp);
1365        }
1366
1367        key_free(public);
1368        exit(0);
1369}
Note: See TracBrowser for help on using the repository browser.