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