Annotation of src/usr.bin/ssh/ssh-keygen.c, Revision 1.46
1.1 deraadt 1: /*
1.13 deraadt 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.
1.31 deraadt 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".
1.13 deraadt 12: */
1.1 deraadt 13:
14: #include "includes.h"
1.46 ! deraadt 15: RCSID("$OpenBSD: ssh-keygen.c,v 1.45 2001/02/22 08:03:51 deraadt Exp $");
1.19 markus 16:
17: #include <openssl/evp.h>
18: #include <openssl/pem.h>
1.1 deraadt 19:
20: #include "xmalloc.h"
1.19 markus 21: #include "key.h"
22: #include "authfile.h"
23: #include "uuencode.h"
1.32 markus 24: #include "buffer.h"
25: #include "bufaux.h"
1.40 markus 26: #include "pathnames.h"
1.41 markus 27: #include "log.h"
28: #include "readpass.h"
1.32 markus 29:
1.19 markus 30: /* Number of bits in the RSA/DSA key. This value can be changed on the command line. */
1.1 deraadt 31: int bits = 1024;
32:
1.14 markus 33: /*
34: * Flag indicating that we just want to change the passphrase. This can be
35: * set on the command line.
36: */
1.1 deraadt 37: int change_passphrase = 0;
38:
1.14 markus 39: /*
40: * Flag indicating that we just want to change the comment. This can be set
41: * on the command line.
42: */
1.1 deraadt 43: int change_comment = 0;
44:
1.2 provos 45: int quiet = 0;
46:
1.8 markus 47: /* Flag indicating that we just want to see the key fingerprint */
48: int print_fingerprint = 0;
49:
1.10 markus 50: /* The identity file name, given on the command line or entered by the user. */
51: char identity_file[1024];
52: int have_identity = 0;
1.1 deraadt 53:
54: /* This is set to the passphrase if given on the command line. */
55: char *identity_passphrase = NULL;
56:
57: /* This is set to the new passphrase if given on the command line. */
58: char *identity_new_passphrase = NULL;
59:
60: /* This is set to the new comment if given on the command line. */
61: char *identity_comment = NULL;
62:
1.19 markus 63: /* Dump public key file in format used by real and the original SSH 2 */
64: int convert_to_ssh2 = 0;
65: int convert_from_ssh2 = 0;
66: int print_public = 0;
1.33 markus 67:
1.35 markus 68: /* default to RSA for SSH-1 */
69: char *key_type_name = "rsa1";
1.19 markus 70:
1.10 markus 71: /* argv0 */
72: extern char *__progname;
1.1 deraadt 73:
1.19 markus 74: char hostname[MAXHOSTNAMELEN];
75:
1.10 markus 76: void
77: ask_filename(struct passwd *pw, const char *prompt)
1.1 deraadt 78: {
1.12 markus 79: char buf[1024];
1.35 markus 80: char *name = NULL;
81:
82: switch (key_type_from_name(key_type_name)) {
83: case KEY_RSA1:
1.40 markus 84: name = _PATH_SSH_CLIENT_IDENTITY;
1.35 markus 85: break;
86: case KEY_DSA:
1.40 markus 87: name = _PATH_SSH_CLIENT_ID_DSA;
1.35 markus 88: break;
89: case KEY_RSA:
1.40 markus 90: name = _PATH_SSH_CLIENT_ID_RSA;
1.35 markus 91: break;
92: default:
93: fprintf(stderr, "bad key type");
94: exit(1);
95: break;
96: }
97: snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name);
1.37 markus 98: fprintf(stderr, "%s (%s): ", prompt, identity_file);
99: fflush(stderr);
1.12 markus 100: if (fgets(buf, sizeof(buf), stdin) == NULL)
101: exit(1);
102: if (strchr(buf, '\n'))
103: *strchr(buf, '\n') = 0;
104: if (strcmp(buf, "") != 0)
105: strlcpy(identity_file, buf, sizeof(identity_file));
106: have_identity = 1;
1.7 markus 107: }
108:
1.19 markus 109: int
110: try_load_key(char *filename, Key *k)
111: {
112: int success = 1;
113: if (!load_private_key(filename, "", k, NULL)) {
114: char *pass = read_passphrase("Enter passphrase: ", 1);
115: if (!load_private_key(filename, pass, k, NULL)) {
116: success = 0;
117: }
118: memset(pass, 0, strlen(pass));
119: xfree(pass);
120: }
121: return success;
122: }
123:
1.32 markus 124: #define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
125: #define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----"
126: #define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
1.42 stevesk 127: #define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb
1.19 markus 128:
129: void
130: do_convert_to_ssh2(struct passwd *pw)
131: {
132: Key *k;
133: int len;
1.36 markus 134: u_char *blob;
1.19 markus 135: struct stat st;
136:
137: if (!have_identity)
138: ask_filename(pw, "Enter file in which the key is");
139: if (stat(identity_file, &st) < 0) {
140: perror(identity_file);
141: exit(1);
142: }
1.33 markus 143: k = key_new(KEY_UNSPEC);
1.19 markus 144: if (!try_load_key(identity_file, k)) {
145: fprintf(stderr, "load failed\n");
146: exit(1);
147: }
1.33 markus 148: key_to_blob(k, &blob, &len);
1.32 markus 149: fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
1.19 markus 150: fprintf(stdout,
1.32 markus 151: "Comment: \"%d-bit %s, converted from OpenSSH by %s@%s\"\n",
152: key_size(k), key_type(k),
1.19 markus 153: pw->pw_name, hostname);
154: dump_base64(stdout, blob, len);
1.32 markus 155: fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
1.19 markus 156: key_free(k);
1.21 markus 157: xfree(blob);
1.19 markus 158: exit(0);
159: }
160:
161: void
1.32 markus 162: buffer_get_bignum_bits(Buffer *b, BIGNUM *value)
163: {
164: int bits = buffer_get_int(b);
165: int bytes = (bits + 7) / 8;
166: if (buffer_len(b) < bytes)
167: fatal("buffer_get_bignum_bits: input buffer too small");
1.36 markus 168: BN_bin2bn((u_char *)buffer_ptr(b), bytes, value);
1.32 markus 169: buffer_consume(b, bytes);
170: }
171:
172: Key *
173: do_convert_private_ssh2_from_blob(char *blob, int blen)
174: {
175: Buffer b;
176: DSA *dsa;
177: Key *key = NULL;
178: int ignore, magic, rlen;
179: char *type, *cipher;
180:
181: buffer_init(&b);
182: buffer_append(&b, blob, blen);
183:
184: magic = buffer_get_int(&b);
185: if (magic != SSH_COM_PRIVATE_KEY_MAGIC) {
186: error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC);
187: buffer_free(&b);
188: return NULL;
189: }
190: ignore = buffer_get_int(&b);
191: type = buffer_get_string(&b, NULL);
192: cipher = buffer_get_string(&b, NULL);
193: ignore = buffer_get_int(&b);
194: ignore = buffer_get_int(&b);
195: ignore = buffer_get_int(&b);
196: xfree(type);
197:
198: if (strcmp(cipher, "none") != 0) {
199: error("unsupported cipher %s", cipher);
200: xfree(cipher);
201: buffer_free(&b);
202: return NULL;
203: }
204: xfree(cipher);
205:
206: key = key_new(KEY_DSA);
207: dsa = key->dsa;
208: dsa->priv_key = BN_new();
209: if (dsa->priv_key == NULL) {
210: error("alloc priv_key failed");
211: key_free(key);
212: return NULL;
213: }
214: buffer_get_bignum_bits(&b, dsa->p);
215: buffer_get_bignum_bits(&b, dsa->g);
216: buffer_get_bignum_bits(&b, dsa->q);
217: buffer_get_bignum_bits(&b, dsa->pub_key);
218: buffer_get_bignum_bits(&b, dsa->priv_key);
219: rlen = buffer_len(&b);
220: if(rlen != 0)
221: error("do_convert_private_ssh2_from_blob: remaining bytes in key blob %d", rlen);
222: buffer_free(&b);
223: return key;
224: }
225:
226: void
1.19 markus 227: do_convert_from_ssh2(struct passwd *pw)
228: {
229: Key *k;
230: int blen;
231: char line[1024], *p;
232: char blob[8096];
233: char encoded[8096];
234: struct stat st;
1.32 markus 235: int escaped = 0, private = 0, ok;
1.19 markus 236: FILE *fp;
237:
238: if (!have_identity)
239: ask_filename(pw, "Enter file in which the key is");
240: if (stat(identity_file, &st) < 0) {
241: perror(identity_file);
242: exit(1);
243: }
244: fp = fopen(identity_file, "r");
245: if (fp == NULL) {
246: perror(identity_file);
247: exit(1);
248: }
249: encoded[0] = '\0';
250: while (fgets(line, sizeof(line), fp)) {
1.25 markus 251: if (!(p = strchr(line, '\n'))) {
252: fprintf(stderr, "input line too long.\n");
253: exit(1);
254: }
255: if (p > line && p[-1] == '\\')
256: escaped++;
1.19 markus 257: if (strncmp(line, "----", 4) == 0 ||
258: strstr(line, ": ") != NULL) {
1.32 markus 259: if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL)
260: private = 1;
1.19 markus 261: fprintf(stderr, "ignore: %s", line);
262: continue;
263: }
1.25 markus 264: if (escaped) {
265: escaped--;
266: fprintf(stderr, "escaped: %s", line);
267: continue;
1.19 markus 268: }
269: *p = '\0';
270: strlcat(encoded, line, sizeof(encoded));
271: }
1.36 markus 272: blen = uudecode(encoded, (u_char *)blob, sizeof(blob));
1.19 markus 273: if (blen < 0) {
274: fprintf(stderr, "uudecode failed.\n");
275: exit(1);
276: }
1.32 markus 277: k = private ?
278: do_convert_private_ssh2_from_blob(blob, blen) :
1.33 markus 279: key_from_blob(blob, blen);
1.32 markus 280: if (k == NULL) {
281: fprintf(stderr, "decode blob failed.\n");
282: exit(1);
283: }
284: ok = private ?
285: PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) :
286: key_write(k, stdout);
287: if (!ok) {
288: fprintf(stderr, "key write failed");
289: exit(1);
290: }
1.19 markus 291: key_free(k);
292: fprintf(stdout, "\n");
293: fclose(fp);
294: exit(0);
295: }
296:
297: void
298: do_print_public(struct passwd *pw)
299: {
300: Key *k;
301: struct stat st;
302:
303: if (!have_identity)
304: ask_filename(pw, "Enter file in which the key is");
305: if (stat(identity_file, &st) < 0) {
306: perror(identity_file);
307: exit(1);
308: }
1.33 markus 309: k = key_new(KEY_UNSPEC);
1.19 markus 310: if (!try_load_key(identity_file, k)) {
311: fprintf(stderr, "load failed\n");
312: exit(1);
313: }
314: if (!key_write(k, stdout))
315: fprintf(stderr, "key_write failed");
316: key_free(k);
317: fprintf(stdout, "\n");
318: exit(0);
319: }
320:
1.7 markus 321: void
1.8 markus 322: do_fingerprint(struct passwd *pw)
323: {
1.30 markus 324:
1.15 markus 325: FILE *f;
1.19 markus 326: Key *public;
1.16 markus 327: char *comment = NULL, *cp, *ep, line[16*1024];
1.33 markus 328: int i, skip = 0, num = 1, invalid = 1, success = 0;
1.12 markus 329: struct stat st;
330:
331: if (!have_identity)
332: ask_filename(pw, "Enter file in which the key is");
333: if (stat(identity_file, &st) < 0) {
334: perror(identity_file);
335: exit(1);
336: }
1.33 markus 337: public = key_new(KEY_RSA1);
1.19 markus 338: if (load_public_key(identity_file, public, &comment)) {
1.33 markus 339: success = 1;
340: } else {
1.19 markus 341: key_free(public);
1.33 markus 342: public = key_new(KEY_UNSPEC);
343: if (try_load_public_key(identity_file, public, &comment))
344: success = 1;
345: else
1.38 markus 346: debug("try_load_public_key KEY_UNSPEC failed");
1.33 markus 347: }
348: if (success) {
349: printf("%d %s %s\n", key_size(public), key_fingerprint(public), comment);
350: key_free(public);
351: xfree(comment);
1.15 markus 352: exit(0);
353: }
354:
355: f = fopen(identity_file, "r");
356: if (f != NULL) {
357: while (fgets(line, sizeof(line), f)) {
358: i = strlen(line) - 1;
359: if (line[i] != '\n') {
360: error("line %d too long: %.40s...", num, line);
361: skip = 1;
362: continue;
363: }
364: num++;
365: if (skip) {
366: skip = 0;
367: continue;
368: }
369: line[i] = '\0';
370:
371: /* Skip leading whitespace, empty and comment lines. */
372: for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
373: ;
374: if (!*cp || *cp == '\n' || *cp == '#')
375: continue ;
376: i = strtol(cp, &ep, 10);
377: if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
378: int quoted = 0;
379: comment = cp;
380: for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
381: if (*cp == '\\' && cp[1] == '"')
382: cp++; /* Skip both */
383: else if (*cp == '"')
384: quoted = !quoted;
385: }
386: if (!*cp)
387: continue;
388: *cp++ = '\0';
389: }
390: ep = cp;
1.38 markus 391: public = key_new(KEY_RSA1);
392: if (key_read(public, &cp) != 1) {
393: cp = ep;
394: key_free(public);
395: public = key_new(KEY_UNSPEC);
396: if (key_read(public, &cp) != 1) {
397: key_free(public);
398: continue;
399: }
1.12 markus 400: }
1.38 markus 401: comment = *cp ? cp : comment;
402: printf("%d %s %s\n", key_size(public),
403: key_fingerprint(public),
404: comment ? comment : "no comment");
405: invalid = 0;
1.12 markus 406: }
1.15 markus 407: fclose(f);
408: }
1.30 markus 409: key_free(public);
1.15 markus 410: if (invalid) {
411: printf("%s is not a valid key file.\n", identity_file);
412: exit(1);
1.12 markus 413: }
414: exit(0);
1.8 markus 415: }
416:
1.13 deraadt 417: /*
418: * Perform changing a passphrase. The argument is the passwd structure
419: * for the current user.
420: */
1.8 markus 421: void
1.7 markus 422: do_change_passphrase(struct passwd *pw)
423: {
1.12 markus 424: char *comment;
425: char *old_passphrase, *passphrase1, *passphrase2;
426: struct stat st;
1.19 markus 427: Key *private;
428: Key *public;
1.33 markus 429: int type = KEY_RSA1;
1.12 markus 430:
431: if (!have_identity)
432: ask_filename(pw, "Enter file in which the key is");
433: if (stat(identity_file, &st) < 0) {
434: perror(identity_file);
435: exit(1);
436: }
1.33 markus 437: public = key_new(type);
438: if (!load_public_key(identity_file, public, NULL)) {
439: type = KEY_UNSPEC;
440: } else {
1.19 markus 441: /* Clear the public key since we are just about to load the whole file. */
442: key_free(public);
1.12 markus 443: }
444: /* Try to load the file with empty passphrase. */
1.19 markus 445: private = key_new(type);
446: if (!load_private_key(identity_file, "", private, &comment)) {
1.12 markus 447: if (identity_passphrase)
448: old_passphrase = xstrdup(identity_passphrase);
449: else
450: old_passphrase = read_passphrase("Enter old passphrase: ", 1);
1.19 markus 451: if (!load_private_key(identity_file, old_passphrase, private, &comment)) {
1.12 markus 452: memset(old_passphrase, 0, strlen(old_passphrase));
453: xfree(old_passphrase);
454: printf("Bad passphrase.\n");
455: exit(1);
456: }
457: memset(old_passphrase, 0, strlen(old_passphrase));
458: xfree(old_passphrase);
459: }
460: printf("Key has comment '%s'\n", comment);
461:
462: /* Ask the new passphrase (twice). */
463: if (identity_new_passphrase) {
464: passphrase1 = xstrdup(identity_new_passphrase);
465: passphrase2 = NULL;
466: } else {
467: passphrase1 =
468: read_passphrase("Enter new passphrase (empty for no passphrase): ", 1);
469: passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
470:
471: /* Verify that they are the same. */
472: if (strcmp(passphrase1, passphrase2) != 0) {
473: memset(passphrase1, 0, strlen(passphrase1));
474: memset(passphrase2, 0, strlen(passphrase2));
475: xfree(passphrase1);
476: xfree(passphrase2);
477: printf("Pass phrases do not match. Try again.\n");
478: exit(1);
479: }
480: /* Destroy the other copy. */
481: memset(passphrase2, 0, strlen(passphrase2));
482: xfree(passphrase2);
483: }
484:
485: /* Save the file using the new passphrase. */
1.19 markus 486: if (!save_private_key(identity_file, passphrase1, private, comment)) {
1.12 markus 487: printf("Saving the key failed: %s: %s.\n",
488: identity_file, strerror(errno));
489: memset(passphrase1, 0, strlen(passphrase1));
490: xfree(passphrase1);
1.19 markus 491: key_free(private);
1.12 markus 492: xfree(comment);
493: exit(1);
494: }
495: /* Destroy the passphrase and the copy of the key in memory. */
496: memset(passphrase1, 0, strlen(passphrase1));
497: xfree(passphrase1);
1.19 markus 498: key_free(private); /* Destroys contents */
1.12 markus 499: xfree(comment);
1.1 deraadt 500:
1.12 markus 501: printf("Your identification has been saved with the new passphrase.\n");
502: exit(0);
1.1 deraadt 503: }
504:
1.13 deraadt 505: /*
506: * Change the comment of a private key file.
507: */
1.2 provos 508: void
509: do_change_comment(struct passwd *pw)
1.1 deraadt 510: {
1.46 ! deraadt 511: char new_comment[1024], *comment, *passphrase;
! 512: Key *private, *public;
1.12 markus 513: struct stat st;
514: FILE *f;
1.46 ! deraadt 515: int fd;
1.12 markus 516:
517: if (!have_identity)
518: ask_filename(pw, "Enter file in which the key is");
519: if (stat(identity_file, &st) < 0) {
520: perror(identity_file);
521: exit(1);
522: }
1.14 markus 523: /*
524: * Try to load the public key from the file the verify that it is
525: * readable and of the proper format.
526: */
1.33 markus 527: public = key_new(KEY_RSA1);
1.19 markus 528: if (!load_public_key(identity_file, public, NULL)) {
1.12 markus 529: printf("%s is not a valid key file.\n", identity_file);
1.43 markus 530: printf("Comments are only supported in RSA1 keys\n");
1.12 markus 531: exit(1);
532: }
1.14 markus 533:
1.33 markus 534: private = key_new(KEY_RSA1);
1.19 markus 535: if (load_private_key(identity_file, "", private, &comment))
1.12 markus 536: passphrase = xstrdup("");
537: else {
538: if (identity_passphrase)
539: passphrase = xstrdup(identity_passphrase);
540: else if (identity_new_passphrase)
541: passphrase = xstrdup(identity_new_passphrase);
542: else
543: passphrase = read_passphrase("Enter passphrase: ", 1);
544: /* Try to load using the passphrase. */
1.19 markus 545: if (!load_private_key(identity_file, passphrase, private, &comment)) {
1.12 markus 546: memset(passphrase, 0, strlen(passphrase));
547: xfree(passphrase);
548: printf("Bad passphrase.\n");
549: exit(1);
550: }
551: }
552: printf("Key now has comment '%s'\n", comment);
553:
554: if (identity_comment) {
555: strlcpy(new_comment, identity_comment, sizeof(new_comment));
556: } else {
557: printf("Enter new comment: ");
558: fflush(stdout);
559: if (!fgets(new_comment, sizeof(new_comment), stdin)) {
560: memset(passphrase, 0, strlen(passphrase));
1.19 markus 561: key_free(private);
1.12 markus 562: exit(1);
563: }
564: if (strchr(new_comment, '\n'))
565: *strchr(new_comment, '\n') = 0;
566: }
567:
568: /* Save the file using the new passphrase. */
1.19 markus 569: if (!save_private_key(identity_file, passphrase, private, new_comment)) {
1.12 markus 570: printf("Saving the key failed: %s: %s.\n",
571: identity_file, strerror(errno));
572: memset(passphrase, 0, strlen(passphrase));
573: xfree(passphrase);
1.19 markus 574: key_free(private);
1.12 markus 575: xfree(comment);
576: exit(1);
577: }
578: memset(passphrase, 0, strlen(passphrase));
579: xfree(passphrase);
1.19 markus 580: key_free(private);
1.12 markus 581:
582: strlcat(identity_file, ".pub", sizeof(identity_file));
1.46 ! deraadt 583: fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
! 584: if (fd == -1) {
1.12 markus 585: printf("Could not save your public key in %s\n", identity_file);
586: exit(1);
587: }
1.46 ! deraadt 588: f = fdopen(fd, "w");
! 589: if (f == NULL) {
! 590: printf("fdopen %s failed", identity_file);
! 591: exit(1);
! 592: }
1.19 markus 593: if (!key_write(public, f))
594: fprintf(stderr, "write key failed");
595: key_free(public);
596: fprintf(f, " %s\n", new_comment);
1.12 markus 597: fclose(f);
1.1 deraadt 598:
1.12 markus 599: xfree(comment);
1.1 deraadt 600:
1.12 markus 601: printf("The comment in your key file has been changed.\n");
602: exit(0);
1.1 deraadt 603: }
604:
1.10 markus 605: void
606: usage(void)
607: {
1.45 deraadt 608: printf("Usage: %s [-lpqxXyc] [-t type] [-b bits] [-f file] [-C comment] "
1.44 deraadt 609: "[-N new-pass] [-P pass]\n", __progname);
1.12 markus 610: exit(1);
1.10 markus 611: }
612:
1.13 deraadt 613: /*
614: * Main program for key management.
615: */
1.2 provos 616: int
617: main(int ac, char **av)
1.1 deraadt 618: {
1.12 markus 619: char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
1.46 ! deraadt 620: Key *private, *public;
1.12 markus 621: struct passwd *pw;
1.46 ! deraadt 622: int opt, type, fd;
1.12 markus 623: struct stat st;
624: FILE *f;
1.33 markus 625:
1.12 markus 626: extern int optind;
627: extern char *optarg;
628:
1.26 markus 629: SSLeay_add_all_algorithms();
1.19 markus 630:
1.14 markus 631: /* we need this for the home * directory. */
1.12 markus 632: pw = getpwuid(getuid());
633: if (!pw) {
634: printf("You don't exist, go away!\n");
635: exit(1);
636: }
1.19 markus 637: if (gethostname(hostname, sizeof(hostname)) < 0) {
638: perror("gethostname");
639: exit(1);
640: }
1.14 markus 641:
1.39 markus 642: while ((opt = getopt(ac, av, "dqpclRxXyb:f:t:P:N:C:")) != -1) {
1.12 markus 643: switch (opt) {
644: case 'b':
645: bits = atoi(optarg);
646: if (bits < 512 || bits > 32768) {
647: printf("Bits has bad value.\n");
648: exit(1);
649: }
650: break;
651:
652: case 'l':
653: print_fingerprint = 1;
654: break;
655:
656: case 'p':
657: change_passphrase = 1;
658: break;
659:
660: case 'c':
661: change_comment = 1;
662: break;
663:
664: case 'f':
665: strlcpy(identity_file, optarg, sizeof(identity_file));
666: have_identity = 1;
667: break;
668:
669: case 'P':
670: identity_passphrase = optarg;
671: break;
672:
673: case 'N':
674: identity_new_passphrase = optarg;
675: break;
676:
677: case 'C':
678: identity_comment = optarg;
679: break;
680:
681: case 'q':
682: quiet = 1;
1.20 deraadt 683: break;
684:
685: case 'R':
1.33 markus 686: /* unused */
687: exit(0);
1.12 markus 688: break;
689:
1.19 markus 690: case 'x':
691: convert_to_ssh2 = 1;
692: break;
693:
694: case 'X':
695: convert_from_ssh2 = 1;
696: break;
697:
698: case 'y':
699: print_public = 1;
700: break;
701:
702: case 'd':
1.33 markus 703: key_type_name = "dsa";
1.19 markus 704: break;
705:
1.33 markus 706: case 't':
707: key_type_name = optarg;
708: break;
709:
1.12 markus 710: case '?':
711: default:
712: usage();
713: }
714: }
715: if (optind < ac) {
716: printf("Too many arguments.\n");
717: usage();
718: }
719: if (change_passphrase && change_comment) {
720: printf("Can only have one of -p and -c.\n");
721: usage();
722: }
723: if (print_fingerprint)
724: do_fingerprint(pw);
725: if (change_passphrase)
726: do_change_passphrase(pw);
727: if (change_comment)
728: do_change_comment(pw);
1.19 markus 729: if (convert_to_ssh2)
730: do_convert_to_ssh2(pw);
731: if (convert_from_ssh2)
732: do_convert_from_ssh2(pw);
733: if (print_public)
734: do_print_public(pw);
1.12 markus 735:
736: arc4random_stir();
737:
1.35 markus 738: type = key_type_from_name(key_type_name);
739: if (type == KEY_UNSPEC) {
740: fprintf(stderr, "unknown key type %s\n", key_type_name);
741: exit(1);
1.19 markus 742: }
1.33 markus 743: if (!quiet)
1.35 markus 744: printf("Generating public/private %s key pair.\n", key_type_name);
1.33 markus 745: private = key_generate(type, bits);
746: if (private == NULL) {
747: fprintf(stderr, "key_generate failed");
748: exit(1);
749: }
750: public = key_from_private(private);
1.12 markus 751:
752: if (!have_identity)
753: ask_filename(pw, "Enter file in which to save the key");
754:
755: /* Create ~/.ssh directory if it doesn\'t already exist. */
1.40 markus 756: snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR);
1.12 markus 757: if (strstr(identity_file, dotsshdir) != NULL &&
758: stat(dotsshdir, &st) < 0) {
1.29 djm 759: if (mkdir(dotsshdir, 0700) < 0)
1.12 markus 760: error("Could not create directory '%s'.", dotsshdir);
761: else if (!quiet)
762: printf("Created directory '%s'.\n", dotsshdir);
763: }
764: /* If the file already exists, ask the user to confirm. */
765: if (stat(identity_file, &st) >= 0) {
766: char yesno[3];
767: printf("%s already exists.\n", identity_file);
768: printf("Overwrite (y/n)? ");
769: fflush(stdout);
770: if (fgets(yesno, sizeof(yesno), stdin) == NULL)
771: exit(1);
772: if (yesno[0] != 'y' && yesno[0] != 'Y')
773: exit(1);
774: }
775: /* Ask for a passphrase (twice). */
776: if (identity_passphrase)
777: passphrase1 = xstrdup(identity_passphrase);
778: else if (identity_new_passphrase)
779: passphrase1 = xstrdup(identity_new_passphrase);
780: else {
781: passphrase_again:
782: passphrase1 =
783: read_passphrase("Enter passphrase (empty for no passphrase): ", 1);
784: passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
785: if (strcmp(passphrase1, passphrase2) != 0) {
786: /* The passphrases do not match. Clear them and retry. */
787: memset(passphrase1, 0, strlen(passphrase1));
788: memset(passphrase2, 0, strlen(passphrase2));
789: xfree(passphrase1);
790: xfree(passphrase2);
791: printf("Passphrases do not match. Try again.\n");
792: goto passphrase_again;
793: }
794: /* Clear the other copy of the passphrase. */
795: memset(passphrase2, 0, strlen(passphrase2));
796: xfree(passphrase2);
797: }
798:
799: if (identity_comment) {
800: strlcpy(comment, identity_comment, sizeof(comment));
801: } else {
1.18 markus 802: /* Create default commend field for the passphrase. */
1.12 markus 803: snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
804: }
805:
806: /* Save the key with the given passphrase and comment. */
1.19 markus 807: if (!save_private_key(identity_file, passphrase1, private, comment)) {
1.12 markus 808: printf("Saving the key failed: %s: %s.\n",
1.19 markus 809: identity_file, strerror(errno));
1.12 markus 810: memset(passphrase1, 0, strlen(passphrase1));
811: xfree(passphrase1);
812: exit(1);
813: }
814: /* Clear the passphrase. */
815: memset(passphrase1, 0, strlen(passphrase1));
816: xfree(passphrase1);
817:
818: /* Clear the private key and the random number generator. */
1.33 markus 819: key_free(private);
1.12 markus 820: arc4random_stir();
821:
822: if (!quiet)
823: printf("Your identification has been saved in %s.\n", identity_file);
824:
825: strlcat(identity_file, ".pub", sizeof(identity_file));
1.46 ! deraadt 826: fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
! 827: if (fd == -1) {
1.12 markus 828: printf("Could not save your public key in %s\n", identity_file);
1.46 ! deraadt 829: exit(1);
! 830: }
! 831: f = fdopen(fd, "w");
! 832: if (f == NULL) {
! 833: printf("fdopen %s failed", identity_file);
1.12 markus 834: exit(1);
835: }
1.19 markus 836: if (!key_write(public, f))
837: fprintf(stderr, "write key failed");
838: fprintf(f, " %s\n", comment);
1.12 markus 839: fclose(f);
840:
841: if (!quiet) {
1.19 markus 842: printf("Your public key has been saved in %s.\n",
843: identity_file);
1.12 markus 844: printf("The key fingerprint is:\n");
1.19 markus 845: printf("%s %s\n", key_fingerprint(public), comment);
1.12 markus 846: }
1.19 markus 847:
848: key_free(public);
1.12 markus 849: exit(0);
1.1 deraadt 850: }