Annotation of src/usr.bin/ssh/ssh-keygen.c, Revision 1.32.2.2
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.32.2.1 jason 15: RCSID("$OpenBSD: ssh-keygen.c,v 1.43 2001/02/12 16:16:23 markus 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.32.2.1 jason 26: #include "pathnames.h"
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.32.2.1 jason 67:
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.32.2.1 jason 80: char *name = NULL;
81:
82: switch (key_type_from_name(key_type_name)) {
83: case KEY_RSA1:
84: name = _PATH_SSH_CLIENT_IDENTITY;
85: break;
86: case KEY_DSA:
87: name = _PATH_SSH_CLIENT_ID_DSA;
88: break;
89: case KEY_RSA:
90: name = _PATH_SSH_CLIENT_ID_RSA;
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);
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.32.2.1 jason 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.32.2.1 jason 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.32.2.1 jason 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.32.2.1 jason 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.32.2.1 jason 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.32.2.1 jason 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.32.2.1 jason 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.32.2.1 jason 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.32.2.1 jason 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.32.2.1 jason 337: public = key_new(KEY_RSA1);
1.19 markus 338: if (load_public_key(identity_file, public, &comment)) {
1.32.2.1 jason 339: success = 1;
340: } else {
341: key_free(public);
342: public = key_new(KEY_UNSPEC);
343: if (try_load_public_key(identity_file, public, &comment))
344: success = 1;
345: else
346: debug("try_load_public_key KEY_UNSPEC failed");
347: }
348: if (success) {
349: printf("%d %s %s\n", key_size(public), key_fingerprint(public), comment);
1.19 markus 350: key_free(public);
1.32.2.1 jason 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.32.2.1 jason 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.32.2.1 jason 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.32.2.1 jason 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.32.2.1 jason 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.12 markus 511: char new_comment[1024], *comment;
1.19 markus 512: Key *private;
513: Key *public;
1.12 markus 514: char *passphrase;
515: struct stat st;
516: FILE *f;
517:
518: if (!have_identity)
519: ask_filename(pw, "Enter file in which the key is");
520: if (stat(identity_file, &st) < 0) {
521: perror(identity_file);
522: exit(1);
523: }
1.14 markus 524: /*
525: * Try to load the public key from the file the verify that it is
526: * readable and of the proper format.
527: */
1.32.2.1 jason 528: public = key_new(KEY_RSA1);
1.19 markus 529: if (!load_public_key(identity_file, public, NULL)) {
1.12 markus 530: printf("%s is not a valid key file.\n", identity_file);
1.32.2.1 jason 531: printf("Comments are only supported in RSA1 keys\n");
1.12 markus 532: exit(1);
533: }
1.14 markus 534:
1.32.2.1 jason 535: private = key_new(KEY_RSA1);
1.19 markus 536: if (load_private_key(identity_file, "", private, &comment))
1.12 markus 537: passphrase = xstrdup("");
538: else {
539: if (identity_passphrase)
540: passphrase = xstrdup(identity_passphrase);
541: else if (identity_new_passphrase)
542: passphrase = xstrdup(identity_new_passphrase);
543: else
544: passphrase = read_passphrase("Enter passphrase: ", 1);
545: /* Try to load using the passphrase. */
1.19 markus 546: if (!load_private_key(identity_file, passphrase, private, &comment)) {
1.12 markus 547: memset(passphrase, 0, strlen(passphrase));
548: xfree(passphrase);
549: printf("Bad passphrase.\n");
550: exit(1);
551: }
552: }
553: printf("Key now has comment '%s'\n", comment);
554:
555: if (identity_comment) {
556: strlcpy(new_comment, identity_comment, sizeof(new_comment));
557: } else {
558: printf("Enter new comment: ");
559: fflush(stdout);
560: if (!fgets(new_comment, sizeof(new_comment), stdin)) {
561: memset(passphrase, 0, strlen(passphrase));
1.19 markus 562: key_free(private);
1.12 markus 563: exit(1);
564: }
565: if (strchr(new_comment, '\n'))
566: *strchr(new_comment, '\n') = 0;
567: }
568:
569: /* Save the file using the new passphrase. */
1.19 markus 570: if (!save_private_key(identity_file, passphrase, private, new_comment)) {
1.12 markus 571: printf("Saving the key failed: %s: %s.\n",
572: identity_file, strerror(errno));
573: memset(passphrase, 0, strlen(passphrase));
574: xfree(passphrase);
1.19 markus 575: key_free(private);
1.12 markus 576: xfree(comment);
577: exit(1);
578: }
579: memset(passphrase, 0, strlen(passphrase));
580: xfree(passphrase);
1.19 markus 581: key_free(private);
1.12 markus 582:
583: strlcat(identity_file, ".pub", sizeof(identity_file));
584: f = fopen(identity_file, "w");
585: if (!f) {
586: printf("Could not save your public key in %s\n", identity_file);
587: exit(1);
588: }
1.19 markus 589: if (!key_write(public, f))
590: fprintf(stderr, "write key failed");
591: key_free(public);
592: fprintf(f, " %s\n", new_comment);
1.12 markus 593: fclose(f);
1.1 deraadt 594:
1.12 markus 595: xfree(comment);
1.1 deraadt 596:
1.12 markus 597: printf("The comment in your key file has been changed.\n");
598: exit(0);
1.1 deraadt 599: }
600:
1.10 markus 601: void
602: usage(void)
603: {
1.32.2.1 jason 604: printf("Usage: %s [-lpqxXyc] [-t type] [-b bits] [-f file] [-C comment] [-N new-pass] [-P pass]\n", __progname);
1.12 markus 605: exit(1);
1.10 markus 606: }
607:
1.13 deraadt 608: /*
609: * Main program for key management.
610: */
1.2 provos 611: int
612: main(int ac, char **av)
1.1 deraadt 613: {
1.12 markus 614: char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
615: struct passwd *pw;
1.32.2.1 jason 616: int opt, type;
1.12 markus 617: struct stat st;
618: FILE *f;
1.19 markus 619: Key *private;
620: Key *public;
1.32.2.1 jason 621:
1.12 markus 622: extern int optind;
623: extern char *optarg;
624:
1.26 markus 625: SSLeay_add_all_algorithms();
1.19 markus 626:
1.14 markus 627: /* we need this for the home * directory. */
1.12 markus 628: pw = getpwuid(getuid());
629: if (!pw) {
630: printf("You don't exist, go away!\n");
631: exit(1);
632: }
1.19 markus 633: if (gethostname(hostname, sizeof(hostname)) < 0) {
634: perror("gethostname");
635: exit(1);
636: }
1.14 markus 637:
1.32.2.1 jason 638: while ((opt = getopt(ac, av, "dqpclRxXyb:f:t:P:N:C:")) != -1) {
1.12 markus 639: switch (opt) {
640: case 'b':
641: bits = atoi(optarg);
642: if (bits < 512 || bits > 32768) {
643: printf("Bits has bad value.\n");
644: exit(1);
645: }
646: break;
647:
648: case 'l':
649: print_fingerprint = 1;
650: break;
651:
652: case 'p':
653: change_passphrase = 1;
654: break;
655:
656: case 'c':
657: change_comment = 1;
658: break;
659:
660: case 'f':
661: strlcpy(identity_file, optarg, sizeof(identity_file));
662: have_identity = 1;
663: break;
664:
665: case 'P':
666: identity_passphrase = optarg;
667: break;
668:
669: case 'N':
670: identity_new_passphrase = optarg;
671: break;
672:
673: case 'C':
674: identity_comment = optarg;
675: break;
676:
677: case 'q':
678: quiet = 1;
1.20 deraadt 679: break;
680:
681: case 'R':
1.32.2.1 jason 682: /* unused */
683: exit(0);
1.12 markus 684: break;
685:
1.19 markus 686: case 'x':
687: convert_to_ssh2 = 1;
688: break;
689:
690: case 'X':
691: convert_from_ssh2 = 1;
692: break;
693:
694: case 'y':
695: print_public = 1;
696: break;
697:
698: case 'd':
1.32.2.1 jason 699: key_type_name = "dsa";
700: break;
701:
702: case 't':
703: key_type_name = optarg;
1.19 markus 704: break;
705:
1.12 markus 706: case '?':
707: default:
708: usage();
709: }
710: }
711: if (optind < ac) {
712: printf("Too many arguments.\n");
713: usage();
714: }
715: if (change_passphrase && change_comment) {
716: printf("Can only have one of -p and -c.\n");
717: usage();
718: }
719: if (print_fingerprint)
720: do_fingerprint(pw);
721: if (change_passphrase)
722: do_change_passphrase(pw);
723: if (change_comment)
724: do_change_comment(pw);
1.19 markus 725: if (convert_to_ssh2)
726: do_convert_to_ssh2(pw);
727: if (convert_from_ssh2)
728: do_convert_from_ssh2(pw);
729: if (print_public)
730: do_print_public(pw);
1.12 markus 731:
732: arc4random_stir();
733:
1.32.2.1 jason 734: type = key_type_from_name(key_type_name);
735: if (type == KEY_UNSPEC) {
736: fprintf(stderr, "unknown key type %s\n", key_type_name);
737: exit(1);
738: }
739: if (!quiet)
740: printf("Generating public/private %s key pair.\n", key_type_name);
741: private = key_generate(type, bits);
742: if (private == NULL) {
743: fprintf(stderr, "key_generate failed");
744: exit(1);
1.19 markus 745: }
1.32.2.1 jason 746: public = key_from_private(private);
1.12 markus 747:
748: if (!have_identity)
749: ask_filename(pw, "Enter file in which to save the key");
750:
751: /* Create ~/.ssh directory if it doesn\'t already exist. */
1.32.2.1 jason 752: snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR);
1.12 markus 753: if (strstr(identity_file, dotsshdir) != NULL &&
754: stat(dotsshdir, &st) < 0) {
1.29 djm 755: if (mkdir(dotsshdir, 0700) < 0)
1.12 markus 756: error("Could not create directory '%s'.", dotsshdir);
757: else if (!quiet)
758: printf("Created directory '%s'.\n", dotsshdir);
759: }
760: /* If the file already exists, ask the user to confirm. */
761: if (stat(identity_file, &st) >= 0) {
762: char yesno[3];
763: printf("%s already exists.\n", identity_file);
764: printf("Overwrite (y/n)? ");
765: fflush(stdout);
766: if (fgets(yesno, sizeof(yesno), stdin) == NULL)
767: exit(1);
768: if (yesno[0] != 'y' && yesno[0] != 'Y')
769: exit(1);
770: }
771: /* Ask for a passphrase (twice). */
772: if (identity_passphrase)
773: passphrase1 = xstrdup(identity_passphrase);
774: else if (identity_new_passphrase)
775: passphrase1 = xstrdup(identity_new_passphrase);
776: else {
777: passphrase_again:
778: passphrase1 =
779: read_passphrase("Enter passphrase (empty for no passphrase): ", 1);
780: passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
781: if (strcmp(passphrase1, passphrase2) != 0) {
782: /* The passphrases do not match. Clear them and retry. */
783: memset(passphrase1, 0, strlen(passphrase1));
784: memset(passphrase2, 0, strlen(passphrase2));
785: xfree(passphrase1);
786: xfree(passphrase2);
787: printf("Passphrases do not match. Try again.\n");
788: goto passphrase_again;
789: }
790: /* Clear the other copy of the passphrase. */
791: memset(passphrase2, 0, strlen(passphrase2));
792: xfree(passphrase2);
793: }
794:
795: if (identity_comment) {
796: strlcpy(comment, identity_comment, sizeof(comment));
797: } else {
1.18 markus 798: /* Create default commend field for the passphrase. */
1.12 markus 799: snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
800: }
801:
802: /* Save the key with the given passphrase and comment. */
1.19 markus 803: if (!save_private_key(identity_file, passphrase1, private, comment)) {
1.12 markus 804: printf("Saving the key failed: %s: %s.\n",
1.19 markus 805: identity_file, strerror(errno));
1.12 markus 806: memset(passphrase1, 0, strlen(passphrase1));
807: xfree(passphrase1);
808: exit(1);
809: }
810: /* Clear the passphrase. */
811: memset(passphrase1, 0, strlen(passphrase1));
812: xfree(passphrase1);
813:
814: /* Clear the private key and the random number generator. */
1.32.2.1 jason 815: key_free(private);
1.12 markus 816: arc4random_stir();
817:
818: if (!quiet)
819: printf("Your identification has been saved in %s.\n", identity_file);
820:
821: strlcat(identity_file, ".pub", sizeof(identity_file));
822: f = fopen(identity_file, "w");
823: if (!f) {
824: printf("Could not save your public key in %s\n", identity_file);
825: exit(1);
826: }
1.19 markus 827: if (!key_write(public, f))
828: fprintf(stderr, "write key failed");
829: fprintf(f, " %s\n", comment);
1.12 markus 830: fclose(f);
831:
832: if (!quiet) {
1.19 markus 833: printf("Your public key has been saved in %s.\n",
834: identity_file);
1.12 markus 835: printf("The key fingerprint is:\n");
1.19 markus 836: printf("%s %s\n", key_fingerprint(public), comment);
1.12 markus 837: }
1.19 markus 838:
839: key_free(public);
1.12 markus 840: exit(0);
1.1 deraadt 841: }