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

Revision 18759, 24.2 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18758, 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.101 2002/06/23 09:39:55 deraadt 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 "readpass.h"
30
31#ifdef SMARTCARD
32#include "scard.h"
33#endif
34
35/* Number of bits in the RSA/DSA key.  This value can be changed on the command line. */
36int bits = 1024;
37
38/*
39 * Flag indicating that we just want to change the passphrase.  This can be
40 * set on the command line.
41 */
42int change_passphrase = 0;
43
44/*
45 * Flag indicating that we just want to change the comment.  This can be set
46 * on the command line.
47 */
48int change_comment = 0;
49
50int quiet = 0;
51
52/* Flag indicating that we just want to see the key fingerprint */
53int print_fingerprint = 0;
54int print_bubblebabble = 0;
55
56/* The identity file name, given on the command line or entered by the user. */
57char identity_file[1024];
58int have_identity = 0;
59
60/* This is set to the passphrase if given on the command line. */
61char *identity_passphrase = NULL;
62
63/* This is set to the new passphrase if given on the command line. */
64char *identity_new_passphrase = NULL;
65
66/* This is set to the new comment if given on the command line. */
67char *identity_comment = NULL;
68
69/* Dump public key file in format used by real and the original SSH 2 */
70int convert_to_ssh2 = 0;
71int convert_from_ssh2 = 0;
72int print_public = 0;
73
74char *key_type_name = NULL;
75
76/* argv0 */
77#ifdef HAVE___PROGNAME
78extern char *__progname;
79#else
80char *__progname;
81#endif
82
83char hostname[MAXHOSTNAMELEN];
84
85static void
86ask_filename(struct passwd *pw, const char *prompt)
87{
88        char buf[1024];
89        char *name = NULL;
90
91        if (key_type_name == NULL)
92                name = _PATH_SSH_CLIENT_ID_RSA;
93        else
94                switch (key_type_from_name(key_type_name)) {
95                case KEY_RSA1:
96                        name = _PATH_SSH_CLIENT_IDENTITY;
97                        break;
98                case KEY_DSA:
99                        name = _PATH_SSH_CLIENT_ID_DSA;
100                        break;
101                case KEY_RSA:
102                        name = _PATH_SSH_CLIENT_ID_RSA;
103                        break;
104                default:
105                        fprintf(stderr, "bad key type");
106                        exit(1);
107                        break;
108                }
109
110        snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name);
111        fprintf(stderr, "%s (%s): ", prompt, identity_file);
112        fflush(stderr);
113        if (fgets(buf, sizeof(buf), stdin) == NULL)
114                exit(1);
115        if (strchr(buf, '\n'))
116                *strchr(buf, '\n') = 0;
117        if (strcmp(buf, "") != 0)
118                strlcpy(identity_file, buf, sizeof(identity_file));
119        have_identity = 1;
120}
121
122static Key *
123load_identity(char *filename)
124{
125        char *pass;
126        Key *prv;
127
128        prv = key_load_private(filename, "", NULL);
129        if (prv == NULL) {
130                if (identity_passphrase)
131                        pass = xstrdup(identity_passphrase);
132                else
133                        pass = read_passphrase("Enter passphrase: ",
134                            RP_ALLOW_STDIN);
135                prv = key_load_private(filename, pass, NULL);
136                memset(pass, 0, strlen(pass));
137                xfree(pass);
138        }
139        return prv;
140}
141
142#define SSH_COM_PUBLIC_BEGIN            "---- BEGIN SSH2 PUBLIC KEY ----"
143#define SSH_COM_PUBLIC_END              "---- END SSH2 PUBLIC KEY ----"
144#define SSH_COM_PRIVATE_BEGIN           "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
145#define SSH_COM_PRIVATE_KEY_MAGIC       0x3f6ff9eb
146
147static void
148do_convert_to_ssh2(struct passwd *pw)
149{
150        Key *k;
151        u_int len;
152        u_char *blob;
153        struct stat st;
154
155        if (!have_identity)
156                ask_filename(pw, "Enter file in which the key is");
157        if (stat(identity_file, &st) < 0) {
158                perror(identity_file);
159                exit(1);
160        }
161        if ((k = key_load_public(identity_file, NULL)) == NULL) {
162                if ((k = load_identity(identity_file)) == NULL) {
163                        fprintf(stderr, "load failed\n");
164                        exit(1);
165                }
166        }
167        if (key_to_blob(k, &blob, &len) <= 0) {
168                fprintf(stderr, "key_to_blob failed\n");
169                exit(1);
170        }
171        fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
172        fprintf(stdout,
173            "Comment: \"%u-bit %s, converted from OpenSSH by %s@%s\"\n",
174            key_size(k), key_type(k),
175            pw->pw_name, hostname);
176        dump_base64(stdout, blob, len);
177        fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
178        key_free(k);
179        xfree(blob);
180        exit(0);
181}
182
183static void
184buffer_get_bignum_bits(Buffer *b, BIGNUM *value)
185{
186        int bits = buffer_get_int(b);
187        int bytes = (bits + 7) / 8;
188
189        if (buffer_len(b) < bytes)
190                fatal("buffer_get_bignum_bits: input buffer too small: "
191                    "need %d have %d", bytes, buffer_len(b));
192        BN_bin2bn(buffer_ptr(b), bytes, value);
193        buffer_consume(b, bytes);
194}
195
196static Key *
197do_convert_private_ssh2_from_blob(u_char *blob, u_int blen)
198{
199        Buffer b;
200        Key *key = NULL;
201        char *type, *cipher;
202        u_char *sig, data[] = "abcde12345";
203        int magic, rlen, ktype, i1, i2, i3, i4;
204        u_int slen;
205        u_long e;
206
207        buffer_init(&b);
208        buffer_append(&b, blob, blen);
209
210        magic  = buffer_get_int(&b);
211        if (magic != SSH_COM_PRIVATE_KEY_MAGIC) {
212                error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC);
213                buffer_free(&b);
214                return NULL;
215        }
216        i1 = buffer_get_int(&b);
217        type   = buffer_get_string(&b, NULL);
218        cipher = buffer_get_string(&b, NULL);
219        i2 = buffer_get_int(&b);
220        i3 = buffer_get_int(&b);
221        i4 = buffer_get_int(&b);
222        debug("ignore (%d %d %d %d)", i1,i2,i3,i4);
223        if (strcmp(cipher, "none") != 0) {
224                error("unsupported cipher %s", cipher);
225                xfree(cipher);
226                buffer_free(&b);
227                xfree(type);
228                return NULL;
229        }
230        xfree(cipher);
231
232        if (strstr(type, "dsa")) {
233                ktype = KEY_DSA;
234        } else if (strstr(type, "rsa")) {
235                ktype = KEY_RSA;
236        } else {
237                xfree(type);
238                return NULL;
239        }
240        key = key_new_private(ktype);
241        xfree(type);
242
243        switch (key->type) {
244        case KEY_DSA:
245                buffer_get_bignum_bits(&b, key->dsa->p);
246                buffer_get_bignum_bits(&b, key->dsa->g);
247                buffer_get_bignum_bits(&b, key->dsa->q);
248                buffer_get_bignum_bits(&b, key->dsa->pub_key);
249                buffer_get_bignum_bits(&b, key->dsa->priv_key);
250                break;
251        case KEY_RSA:
252                e  = buffer_get_char(&b);
253                debug("e %lx", e);
254                if (e < 30) {
255                        e <<= 8;
256                        e += buffer_get_char(&b);
257                        debug("e %lx", e);
258                        e <<= 8;
259                        e += buffer_get_char(&b);
260                        debug("e %lx", e);
261                }
262                if (!BN_set_word(key->rsa->e, e)) {
263                        buffer_free(&b);
264                        key_free(key);
265                        return NULL;
266                }
267                buffer_get_bignum_bits(&b, key->rsa->d);
268                buffer_get_bignum_bits(&b, key->rsa->n);
269                buffer_get_bignum_bits(&b, key->rsa->iqmp);
270                buffer_get_bignum_bits(&b, key->rsa->q);
271                buffer_get_bignum_bits(&b, key->rsa->p);
272                rsa_generate_additional_parameters(key->rsa);
273                break;
274        }
275        rlen = buffer_len(&b);
276        if (rlen != 0)
277                error("do_convert_private_ssh2_from_blob: "
278                    "remaining bytes in key blob %d", rlen);
279        buffer_free(&b);
280
281        /* try the key */
282        key_sign(key, &sig, &slen, data, sizeof(data));
283        key_verify(key, sig, slen, data, sizeof(data));
284        xfree(sig);
285        return key;
286}
287
288static void
289do_convert_from_ssh2(struct passwd *pw)
290{
291        Key *k;
292        int blen;
293        u_int len;
294        char line[1024], *p;
295        u_char blob[8096];
296        char encoded[8096];
297        struct stat st;
298        int escaped = 0, private = 0, ok;
299        FILE *fp;
300
301        if (!have_identity)
302                ask_filename(pw, "Enter file in which the key is");
303        if (stat(identity_file, &st) < 0) {
304                perror(identity_file);
305                exit(1);
306        }
307        fp = fopen(identity_file, "r");
308        if (fp == NULL) {
309                perror(identity_file);
310                exit(1);
311        }
312        encoded[0] = '\0';
313        while (fgets(line, sizeof(line), fp)) {
314                if (!(p = strchr(line, '\n'))) {
315                        fprintf(stderr, "input line too long.\n");
316                        exit(1);
317                }
318                if (p > line && p[-1] == '\\')
319                        escaped++;
320                if (strncmp(line, "----", 4) == 0 ||
321                    strstr(line, ": ") != NULL) {
322                        if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL)
323                                private = 1;
324                        if (strstr(line, " END ") != NULL) {
325                                break;
326                        }
327                        /* fprintf(stderr, "ignore: %s", line); */
328                        continue;
329                }
330                if (escaped) {
331                        escaped--;
332                        /* fprintf(stderr, "escaped: %s", line); */
333                        continue;
334                }
335                *p = '\0';
336                strlcat(encoded, line, sizeof(encoded));
337        }
338        len = strlen(encoded);
339        if (((len % 4) == 3) &&
340            (encoded[len-1] == '=') &&
341            (encoded[len-2] == '=') &&
342            (encoded[len-3] == '='))
343                encoded[len-3] = '\0';
344        blen = uudecode(encoded, blob, sizeof(blob));
345        if (blen < 0) {
346                fprintf(stderr, "uudecode failed.\n");
347                exit(1);
348        }
349        k = private ?
350            do_convert_private_ssh2_from_blob(blob, blen) :
351            key_from_blob(blob, blen);
352        if (k == NULL) {
353                fprintf(stderr, "decode blob failed.\n");
354                exit(1);
355        }
356        ok = private ?
357            (k->type == KEY_DSA ?
358                 PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) :
359                 PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) :
360            key_write(k, stdout);
361        if (!ok) {
362                fprintf(stderr, "key write failed");
363                exit(1);
364        }
365        key_free(k);
366        if (!private)
367                fprintf(stdout, "\n");
368        fclose(fp);
369        exit(0);
370}
371
372static void
373do_print_public(struct passwd *pw)
374{
375        Key *prv;
376        struct stat st;
377
378        if (!have_identity)
379                ask_filename(pw, "Enter file in which the key is");
380        if (stat(identity_file, &st) < 0) {
381                perror(identity_file);
382                exit(1);
383        }
384        prv = load_identity(identity_file);
385        if (prv == NULL) {
386                fprintf(stderr, "load failed\n");
387                exit(1);
388        }
389        if (!key_write(prv, stdout))
390                fprintf(stderr, "key_write failed");
391        key_free(prv);
392        fprintf(stdout, "\n");
393        exit(0);
394}
395
396#ifdef SMARTCARD
397static void
398do_upload(struct passwd *pw, const char *sc_reader_id)
399{
400        Key *prv = NULL;
401        struct stat st;
402        int ret;
403
404        if (!have_identity)
405                ask_filename(pw, "Enter file in which the key is");
406        if (stat(identity_file, &st) < 0) {
407                perror(identity_file);
408                exit(1);
409        }
410        prv = load_identity(identity_file);
411        if (prv == NULL) {
412                error("load failed");
413                exit(1);
414        }
415        ret = sc_put_key(prv, sc_reader_id);
416        key_free(prv);
417        if (ret < 0)
418                exit(1);
419        log("loading key done");
420        exit(0);
421}
422
423static void
424do_download(struct passwd *pw, const char *sc_reader_id)
425{
426        Key **keys = NULL;
427        int i;
428
429        keys = sc_get_keys(sc_reader_id, NULL);
430        if (keys == NULL)
431                fatal("cannot read public key from smartcard");
432        for (i = 0; keys[i]; i++) {
433                key_write(keys[i], stdout);
434                key_free(keys[i]);
435                fprintf(stdout, "\n");
436        }
437        xfree(keys);
438        exit(0);
439}
440#endif /* SMARTCARD */
441
442static void
443do_fingerprint(struct passwd *pw)
444{
445        FILE *f;
446        Key *public;
447        char *comment = NULL, *cp, *ep, line[16*1024], *fp;
448        int i, skip = 0, num = 1, invalid = 1;
449        enum fp_rep rep;
450        enum fp_type fptype;
451        struct stat st;
452
453        fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
454        rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
455
456        if (!have_identity)
457                ask_filename(pw, "Enter file in which the key is");
458        if (stat(identity_file, &st) < 0) {
459                perror(identity_file);
460                exit(1);
461        }
462        public = key_load_public(identity_file, &comment);
463        if (public != NULL) {
464                fp = key_fingerprint(public, fptype, rep);
465                printf("%u %s %s\n", key_size(public), fp, comment);
466                key_free(public);
467                xfree(comment);
468                xfree(fp);
469                exit(0);
470        }
471        if (comment)
472                xfree(comment);
473
474        f = fopen(identity_file, "r");
475        if (f != NULL) {
476                while (fgets(line, sizeof(line), f)) {
477                        i = strlen(line) - 1;
478                        if (line[i] != '\n') {
479                                error("line %d too long: %.40s...", num, line);
480                                skip = 1;
481                                continue;
482                        }
483                        num++;
484                        if (skip) {
485                                skip = 0;
486                                continue;
487                        }
488                        line[i] = '\0';
489
490                        /* Skip leading whitespace, empty and comment lines. */
491                        for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
492                                ;
493                        if (!*cp || *cp == '\n' || *cp == '#')
494                                continue ;
495                        i = strtol(cp, &ep, 10);
496                        if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
497                                int quoted = 0;
498                                comment = cp;
499                                for (; *cp && (quoted || (*cp != ' ' &&
500                                    *cp != '\t')); cp++) {
501                                        if (*cp == '\\' && cp[1] == '"')
502                                                cp++;   /* Skip both */
503                                        else if (*cp == '"')
504                                                quoted = !quoted;
505                                }
506                                if (!*cp)
507                                        continue;
508                                *cp++ = '\0';
509                        }
510                        ep = cp;
511                        public = key_new(KEY_RSA1);
512                        if (key_read(public, &cp) != 1) {
513                                cp = ep;
514                                key_free(public);
515                                public = key_new(KEY_UNSPEC);
516                                if (key_read(public, &cp) != 1) {
517                                        key_free(public);
518                                        continue;
519                                }
520                        }
521                        comment = *cp ? cp : comment;
522                        fp = key_fingerprint(public, fptype, rep);
523                        printf("%u %s %s\n", key_size(public), fp,
524                            comment ? comment : "no comment");
525                        xfree(fp);
526                        key_free(public);
527                        invalid = 0;
528                }
529                fclose(f);
530        }
531        if (invalid) {
532                printf("%s is not a public key file.\n", identity_file);
533                exit(1);
534        }
535        exit(0);
536}
537
538/*
539 * Perform changing a passphrase.  The argument is the passwd structure
540 * for the current user.
541 */
542static void
543do_change_passphrase(struct passwd *pw)
544{
545        char *comment;
546        char *old_passphrase, *passphrase1, *passphrase2;
547        struct stat st;
548        Key *private;
549
550        if (!have_identity)
551                ask_filename(pw, "Enter file in which the key is");
552        if (stat(identity_file, &st) < 0) {
553                perror(identity_file);
554                exit(1);
555        }
556        /* Try to load the file with empty passphrase. */
557        private = key_load_private(identity_file, "", &comment);
558        if (private == NULL) {
559                if (identity_passphrase)
560                        old_passphrase = xstrdup(identity_passphrase);
561                else
562                        old_passphrase =
563                            read_passphrase("Enter old passphrase: ",
564                            RP_ALLOW_STDIN);
565                private = key_load_private(identity_file, old_passphrase,
566                    &comment);
567                memset(old_passphrase, 0, strlen(old_passphrase));
568                xfree(old_passphrase);
569                if (private == NULL) {
570                        printf("Bad passphrase.\n");
571                        exit(1);
572                }
573        }
574        printf("Key has comment '%s'\n", comment);
575
576        /* Ask the new passphrase (twice). */
577        if (identity_new_passphrase) {
578                passphrase1 = xstrdup(identity_new_passphrase);
579                passphrase2 = NULL;
580        } else {
581                passphrase1 =
582                        read_passphrase("Enter new passphrase (empty for no "
583                            "passphrase): ", RP_ALLOW_STDIN);
584                passphrase2 = read_passphrase("Enter same passphrase again: ",
585                    RP_ALLOW_STDIN);
586
587                /* Verify that they are the same. */
588                if (strcmp(passphrase1, passphrase2) != 0) {
589                        memset(passphrase1, 0, strlen(passphrase1));
590                        memset(passphrase2, 0, strlen(passphrase2));
591                        xfree(passphrase1);
592                        xfree(passphrase2);
593                        printf("Pass phrases do not match.  Try again.\n");
594                        exit(1);
595                }
596                /* Destroy the other copy. */
597                memset(passphrase2, 0, strlen(passphrase2));
598                xfree(passphrase2);
599        }
600
601        /* Save the file using the new passphrase. */
602        if (!key_save_private(private, identity_file, passphrase1, comment)) {
603                printf("Saving the key failed: %s.\n", identity_file);
604                memset(passphrase1, 0, strlen(passphrase1));
605                xfree(passphrase1);
606                key_free(private);
607                xfree(comment);
608                exit(1);
609        }
610        /* Destroy the passphrase and the copy of the key in memory. */
611        memset(passphrase1, 0, strlen(passphrase1));
612        xfree(passphrase1);
613        key_free(private);               /* Destroys contents */
614        xfree(comment);
615
616        printf("Your identification has been saved with the new passphrase.\n");
617        exit(0);
618}
619
620/*
621 * Change the comment of a private key file.
622 */
623static void
624do_change_comment(struct passwd *pw)
625{
626        char new_comment[1024], *comment, *passphrase;
627        Key *private;
628        Key *public;
629        struct stat st;
630        FILE *f;
631        int fd;
632
633        if (!have_identity)
634                ask_filename(pw, "Enter file in which the key is");
635        if (stat(identity_file, &st) < 0) {
636                perror(identity_file);
637                exit(1);
638        }
639        private = key_load_private(identity_file, "", &comment);
640        if (private == NULL) {
641                if (identity_passphrase)
642                        passphrase = xstrdup(identity_passphrase);
643                else if (identity_new_passphrase)
644                        passphrase = xstrdup(identity_new_passphrase);
645                else
646                        passphrase = read_passphrase("Enter passphrase: ",
647                            RP_ALLOW_STDIN);
648                /* Try to load using the passphrase. */
649                private = key_load_private(identity_file, passphrase, &comment);
650                if (private == NULL) {
651                        memset(passphrase, 0, strlen(passphrase));
652                        xfree(passphrase);
653                        printf("Bad passphrase.\n");
654                        exit(1);
655                }
656        } else {
657                passphrase = xstrdup("");
658        }
659        if (private->type != KEY_RSA1) {
660                fprintf(stderr, "Comments are only supported for RSA1 keys.\n");
661                key_free(private);
662                exit(1);
663        }
664        printf("Key now has comment '%s'\n", comment);
665
666        if (identity_comment) {
667                strlcpy(new_comment, identity_comment, sizeof(new_comment));
668        } else {
669                printf("Enter new comment: ");
670                fflush(stdout);
671                if (!fgets(new_comment, sizeof(new_comment), stdin)) {
672                        memset(passphrase, 0, strlen(passphrase));
673                        key_free(private);
674                        exit(1);
675                }
676                if (strchr(new_comment, '\n'))
677                        *strchr(new_comment, '\n') = 0;
678        }
679
680        /* Save the file using the new passphrase. */
681        if (!key_save_private(private, identity_file, passphrase, new_comment)) {
682                printf("Saving the key failed: %s.\n", identity_file);
683                memset(passphrase, 0, strlen(passphrase));
684                xfree(passphrase);
685                key_free(private);
686                xfree(comment);
687                exit(1);
688        }
689        memset(passphrase, 0, strlen(passphrase));
690        xfree(passphrase);
691        public = key_from_private(private);
692        key_free(private);
693
694        strlcat(identity_file, ".pub", sizeof(identity_file));
695        fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
696        if (fd == -1) {
697                printf("Could not save your public key in %s\n", identity_file);
698                exit(1);
699        }
700        f = fdopen(fd, "w");
701        if (f == NULL) {
702                printf("fdopen %s failed", identity_file);
703                exit(1);
704        }
705        if (!key_write(public, f))
706                fprintf(stderr, "write key failed");
707        key_free(public);
708        fprintf(f, " %s\n", new_comment);
709        fclose(f);
710
711        xfree(comment);
712
713        printf("The comment in your key file has been changed.\n");
714        exit(0);
715}
716
717static void
718usage(void)
719{
720        fprintf(stderr, "Usage: %s [options]\n", __progname);
721        fprintf(stderr, "Options:\n");
722        fprintf(stderr, "  -b bits     Number of bits in the key to create.\n");
723        fprintf(stderr, "  -c          Change comment in private and public key files.\n");
724        fprintf(stderr, "  -e          Convert OpenSSH to IETF SECSH key file.\n");
725        fprintf(stderr, "  -f filename Filename of the key file.\n");
726        fprintf(stderr, "  -i          Convert IETF SECSH to OpenSSH key file.\n");
727        fprintf(stderr, "  -l          Show fingerprint of key file.\n");
728        fprintf(stderr, "  -p          Change passphrase of private key file.\n");
729        fprintf(stderr, "  -q          Quiet.\n");
730        fprintf(stderr, "  -y          Read private key file and print public key.\n");
731        fprintf(stderr, "  -t type     Specify type of key to create.\n");
732        fprintf(stderr, "  -B          Show bubblebabble digest of key file.\n");
733        fprintf(stderr, "  -C comment  Provide new comment.\n");
734        fprintf(stderr, "  -N phrase   Provide new passphrase.\n");
735        fprintf(stderr, "  -P phrase   Provide old passphrase.\n");
736#ifdef SMARTCARD
737        fprintf(stderr, "  -D reader   Download public key from smartcard.\n");
738        fprintf(stderr, "  -U reader   Upload private key to smartcard.\n");
739#endif /* SMARTCARD */
740
741        exit(1);
742}
743
744/*
745 * Main program for key management.
746 */
747int
748main(int ac, char **av)
749{
750        char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2;
751        char *reader_id = NULL;
752        Key *private, *public;
753        struct passwd *pw;
754        struct stat st;
755        int opt, type, fd, download = 0;
756        FILE *f;
757
758        extern int optind;
759        extern char *optarg;
760
761        __progname = get_progname(av[0]);
762
763        SSLeay_add_all_algorithms();
764        init_rng();
765        seed_rng();
766
767        /* we need this for the home * directory.  */
768        pw = getpwuid(getuid());
769        if (!pw) {
770                printf("You don't exist, go away!\n");
771                exit(1);
772        }
773        if (gethostname(hostname, sizeof(hostname)) < 0) {
774                perror("gethostname");
775                exit(1);
776        }
777
778        while ((opt = getopt(ac, av, "deiqpclBRxXyb:f:t:U:D:P:N:C:")) != -1) {
779                switch (opt) {
780                case 'b':
781                        bits = atoi(optarg);
782                        if (bits < 512 || bits > 32768) {
783                                printf("Bits has bad value.\n");
784                                exit(1);
785                        }
786                        break;
787                case 'l':
788                        print_fingerprint = 1;
789                        break;
790                case 'B':
791                        print_bubblebabble = 1;
792                        break;
793                case 'p':
794                        change_passphrase = 1;
795                        break;
796                case 'c':
797                        change_comment = 1;
798                        break;
799                case 'f':
800                        strlcpy(identity_file, optarg, sizeof(identity_file));
801                        have_identity = 1;
802                        break;
803                case 'P':
804                        identity_passphrase = optarg;
805                        break;
806                case 'N':
807                        identity_new_passphrase = optarg;
808                        break;
809                case 'C':
810                        identity_comment = optarg;
811                        break;
812                case 'q':
813                        quiet = 1;
814                        break;
815                case 'R':
816                        /* unused */
817                        exit(0);
818                        break;
819                case 'e':
820                case 'x':
821                        /* export key */
822                        convert_to_ssh2 = 1;
823                        break;
824                case 'i':
825                case 'X':
826                        /* import key */
827                        convert_from_ssh2 = 1;
828                        break;
829                case 'y':
830                        print_public = 1;
831                        break;
832                case 'd':
833                        key_type_name = "dsa";
834                        break;
835                case 't':
836                        key_type_name = optarg;
837                        break;
838                case 'D':
839                        download = 1;
840                case 'U':
841                        reader_id = optarg;
842                        break;
843                case '?':
844                default:
845                        usage();
846                }
847        }
848        if (optind < ac) {
849                printf("Too many arguments.\n");
850                usage();
851        }
852        if (change_passphrase && change_comment) {
853                printf("Can only have one of -p and -c.\n");
854                usage();
855        }
856        if (print_fingerprint || print_bubblebabble)
857                do_fingerprint(pw);
858        if (change_passphrase)
859                do_change_passphrase(pw);
860        if (change_comment)
861                do_change_comment(pw);
862        if (convert_to_ssh2)
863                do_convert_to_ssh2(pw);
864        if (convert_from_ssh2)
865                do_convert_from_ssh2(pw);
866        if (print_public)
867                do_print_public(pw);
868        if (reader_id != NULL) {
869#ifdef SMARTCARD
870                if (download)
871                        do_download(pw, reader_id);
872                else
873                        do_upload(pw, reader_id);
874#else /* SMARTCARD */
875                fatal("no support for smartcards.");
876#endif /* SMARTCARD */
877        }
878
879        arc4random_stir();
880
881        if (key_type_name == NULL) {
882                printf("You must specify a key type (-t).\n");
883                usage();
884        }
885        type = key_type_from_name(key_type_name);
886        if (type == KEY_UNSPEC) {
887                fprintf(stderr, "unknown key type %s\n", key_type_name);
888                exit(1);
889        }
890        if (!quiet)
891                printf("Generating public/private %s key pair.\n", key_type_name);
892        private = key_generate(type, bits);
893        if (private == NULL) {
894                fprintf(stderr, "key_generate failed");
895                exit(1);
896        }
897        public  = key_from_private(private);
898
899        if (!have_identity)
900                ask_filename(pw, "Enter file in which to save the key");
901
902        /* Create ~/.ssh directory if it doesn\'t already exist. */
903        snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR);
904        if (strstr(identity_file, dotsshdir) != NULL &&
905            stat(dotsshdir, &st) < 0) {
906                if (mkdir(dotsshdir, 0700) < 0)
907                        error("Could not create directory '%s'.", dotsshdir);
908                else if (!quiet)
909                        printf("Created directory '%s'.\n", dotsshdir);
910        }
911        /* If the file already exists, ask the user to confirm. */
912        if (stat(identity_file, &st) >= 0) {
913                char yesno[3];
914                printf("%s already exists.\n", identity_file);
915                printf("Overwrite (y/n)? ");
916                fflush(stdout);
917                if (fgets(yesno, sizeof(yesno), stdin) == NULL)
918                        exit(1);
919                if (yesno[0] != 'y' && yesno[0] != 'Y')
920                        exit(1);
921        }
922        /* Ask for a passphrase (twice). */
923        if (identity_passphrase)
924                passphrase1 = xstrdup(identity_passphrase);
925        else if (identity_new_passphrase)
926                passphrase1 = xstrdup(identity_new_passphrase);
927        else {
928passphrase_again:
929                passphrase1 =
930                        read_passphrase("Enter passphrase (empty for no "
931                            "passphrase): ", RP_ALLOW_STDIN);
932                passphrase2 = read_passphrase("Enter same passphrase again: ",
933                    RP_ALLOW_STDIN);
934                if (strcmp(passphrase1, passphrase2) != 0) {
935                        /*
936                         * The passphrases do not match.  Clear them and
937                         * retry.
938                         */
939                        memset(passphrase1, 0, strlen(passphrase1));
940                        memset(passphrase2, 0, strlen(passphrase2));
941                        xfree(passphrase1);
942                        xfree(passphrase2);
943                        printf("Passphrases do not match.  Try again.\n");
944                        goto passphrase_again;
945                }
946                /* Clear the other copy of the passphrase. */
947                memset(passphrase2, 0, strlen(passphrase2));
948                xfree(passphrase2);
949        }
950
951        if (identity_comment) {
952                strlcpy(comment, identity_comment, sizeof(comment));
953        } else {
954                /* Create default commend field for the passphrase. */
955                snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
956        }
957
958        /* Save the key with the given passphrase and comment. */
959        if (!key_save_private(private, identity_file, passphrase1, comment)) {
960                printf("Saving the key failed: %s.\n", identity_file);
961                memset(passphrase1, 0, strlen(passphrase1));
962                xfree(passphrase1);
963                exit(1);
964        }
965        /* Clear the passphrase. */
966        memset(passphrase1, 0, strlen(passphrase1));
967        xfree(passphrase1);
968
969        /* Clear the private key and the random number generator. */
970        key_free(private);
971        arc4random_stir();
972
973        if (!quiet)
974                printf("Your identification has been saved in %s.\n", identity_file);
975
976        strlcat(identity_file, ".pub", sizeof(identity_file));
977        fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
978        if (fd == -1) {
979                printf("Could not save your public key in %s\n", identity_file);
980                exit(1);
981        }
982        f = fdopen(fd, "w");
983        if (f == NULL) {
984                printf("fdopen %s failed", identity_file);
985                exit(1);
986        }
987        if (!key_write(public, f))
988                fprintf(stderr, "write key failed");
989        fprintf(f, " %s\n", comment);
990        fclose(f);
991
992        if (!quiet) {
993                char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
994                printf("Your public key has been saved in %s.\n",
995                    identity_file);
996                printf("The key fingerprint is:\n");
997                printf("%s %s\n", fp, comment);
998                xfree(fp);
999        }
1000
1001        key_free(public);
1002        exit(0);
1003}
Note: See TracBrowser for help on using the repository browser.