Annotation of src/usr.bin/ssh/ssh-keygen.c, Revision 1.25.2.5
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.25.2.3 jason 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.25.2.5! jason 15: RCSID("$OpenBSD: ssh-keygen.c,v 1.50 2001/03/12 22:02:02 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.25.2.3 jason 24: #include "buffer.h"
25: #include "bufaux.h"
1.25.2.4 jason 26: #include "pathnames.h"
27: #include "log.h"
28: #include "readpass.h"
1.25.2.3 jason 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;
1.25.2.5! jason 49: int print_bubblebabble = 0;
1.8 markus 50:
1.10 markus 51: /* The identity file name, given on the command line or entered by the user. */
52: char identity_file[1024];
53: int have_identity = 0;
1.1 deraadt 54:
55: /* This is set to the passphrase if given on the command line. */
56: char *identity_passphrase = NULL;
57:
58: /* This is set to the new passphrase if given on the command line. */
59: char *identity_new_passphrase = NULL;
60:
61: /* This is set to the new comment if given on the command line. */
62: char *identity_comment = NULL;
63:
1.19 markus 64: /* Dump public key file in format used by real and the original SSH 2 */
65: int convert_to_ssh2 = 0;
66: int convert_from_ssh2 = 0;
67: int print_public = 0;
1.25.2.4 jason 68:
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.25.2.4 jason 81: char *name = NULL;
82:
83: switch (key_type_from_name(key_type_name)) {
84: case KEY_RSA1:
85: name = _PATH_SSH_CLIENT_IDENTITY;
86: break;
87: case KEY_DSA:
88: name = _PATH_SSH_CLIENT_ID_DSA;
89: break;
90: case KEY_RSA:
91: name = _PATH_SSH_CLIENT_ID_RSA;
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);
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.25.2.3 jason 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.25.2.4 jason 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.25.2.4 jason 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.25.2.4 jason 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.25.2.4 jason 149: key_to_blob(k, &blob, &len);
1.25.2.3 jason 150: fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
1.19 markus 151: fprintf(stdout,
1.25.2.3 jason 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.25.2.3 jason 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.25.2.3 jason 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.25.2.4 jason 169: BN_bin2bn((u_char *)buffer_ptr(b), bytes, value);
1.25.2.3 jason 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.25.2.3 jason 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.25.2.3 jason 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.25.2.4 jason 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.25.2.3 jason 278: k = private ?
279: do_convert_private_ssh2_from_blob(blob, blen) :
1.25.2.4 jason 280: key_from_blob(blob, blen);
1.25.2.3 jason 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.25.2.4 jason 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.15 markus 325: FILE *f;
1.19 markus 326: Key *public;
1.25.2.5! jason 327: char *comment = NULL, *cp, *ep, line[16*1024], *fp;
! 328: int i, skip = 0, num = 1, invalid = 1, success = 0, rep, type;
1.12 markus 329: struct stat st;
330:
1.25.2.5! jason 331: type = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
! 332: rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
! 333:
1.12 markus 334: if (!have_identity)
335: ask_filename(pw, "Enter file in which the key is");
336: if (stat(identity_file, &st) < 0) {
337: perror(identity_file);
338: exit(1);
339: }
1.25.2.4 jason 340: public = key_new(KEY_RSA1);
1.19 markus 341: if (load_public_key(identity_file, public, &comment)) {
1.25.2.4 jason 342: success = 1;
343: } else {
344: key_free(public);
345: public = key_new(KEY_UNSPEC);
346: if (try_load_public_key(identity_file, public, &comment))
347: success = 1;
348: else
349: debug("try_load_public_key KEY_UNSPEC failed");
350: }
351: if (success) {
1.25.2.5! jason 352: fp = key_fingerprint(public, type, rep);
! 353: printf("%d %s %s\n", key_size(public),
! 354: fp, comment);
1.19 markus 355: key_free(public);
1.25.2.4 jason 356: xfree(comment);
1.25.2.5! jason 357: xfree(fp);
1.15 markus 358: exit(0);
359: }
360:
361: f = fopen(identity_file, "r");
362: if (f != NULL) {
363: while (fgets(line, sizeof(line), f)) {
364: i = strlen(line) - 1;
365: if (line[i] != '\n') {
366: error("line %d too long: %.40s...", num, line);
367: skip = 1;
368: continue;
369: }
370: num++;
371: if (skip) {
372: skip = 0;
373: continue;
374: }
375: line[i] = '\0';
376:
377: /* Skip leading whitespace, empty and comment lines. */
378: for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
379: ;
380: if (!*cp || *cp == '\n' || *cp == '#')
381: continue ;
382: i = strtol(cp, &ep, 10);
383: if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
384: int quoted = 0;
385: comment = cp;
386: for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
387: if (*cp == '\\' && cp[1] == '"')
388: cp++; /* Skip both */
389: else if (*cp == '"')
390: quoted = !quoted;
391: }
392: if (!*cp)
393: continue;
394: *cp++ = '\0';
395: }
396: ep = cp;
1.25.2.4 jason 397: public = key_new(KEY_RSA1);
398: if (key_read(public, &cp) != 1) {
399: cp = ep;
400: key_free(public);
401: public = key_new(KEY_UNSPEC);
402: if (key_read(public, &cp) != 1) {
403: key_free(public);
404: continue;
405: }
1.12 markus 406: }
1.25.2.4 jason 407: comment = *cp ? cp : comment;
1.25.2.5! jason 408: fp = key_fingerprint(public, type, rep);
! 409: printf("%d %s %s\n", key_size(public), fp,
1.25.2.4 jason 410: comment ? comment : "no comment");
1.25.2.5! jason 411: xfree(fp);
1.25.2.4 jason 412: invalid = 0;
1.12 markus 413: }
1.15 markus 414: fclose(f);
415: }
1.25.2.2 jason 416: key_free(public);
1.15 markus 417: if (invalid) {
418: printf("%s is not a valid key file.\n", identity_file);
419: exit(1);
1.12 markus 420: }
421: exit(0);
1.8 markus 422: }
423:
1.13 deraadt 424: /*
425: * Perform changing a passphrase. The argument is the passwd structure
426: * for the current user.
427: */
1.8 markus 428: void
1.7 markus 429: do_change_passphrase(struct passwd *pw)
430: {
1.12 markus 431: char *comment;
432: char *old_passphrase, *passphrase1, *passphrase2;
433: struct stat st;
1.19 markus 434: Key *private;
435: Key *public;
1.25.2.4 jason 436: int type = KEY_RSA1;
1.12 markus 437:
438: if (!have_identity)
439: ask_filename(pw, "Enter file in which the key is");
440: if (stat(identity_file, &st) < 0) {
441: perror(identity_file);
442: exit(1);
443: }
1.25.2.4 jason 444: public = key_new(type);
445: if (!load_public_key(identity_file, public, NULL)) {
446: type = KEY_UNSPEC;
447: } else {
1.19 markus 448: /* Clear the public key since we are just about to load the whole file. */
449: key_free(public);
1.12 markus 450: }
451: /* Try to load the file with empty passphrase. */
1.19 markus 452: private = key_new(type);
453: if (!load_private_key(identity_file, "", private, &comment)) {
1.12 markus 454: if (identity_passphrase)
455: old_passphrase = xstrdup(identity_passphrase);
456: else
457: old_passphrase = read_passphrase("Enter old passphrase: ", 1);
1.19 markus 458: if (!load_private_key(identity_file, old_passphrase, private, &comment)) {
1.12 markus 459: memset(old_passphrase, 0, strlen(old_passphrase));
460: xfree(old_passphrase);
461: printf("Bad passphrase.\n");
462: exit(1);
463: }
464: memset(old_passphrase, 0, strlen(old_passphrase));
465: xfree(old_passphrase);
466: }
467: printf("Key has comment '%s'\n", comment);
468:
469: /* Ask the new passphrase (twice). */
470: if (identity_new_passphrase) {
471: passphrase1 = xstrdup(identity_new_passphrase);
472: passphrase2 = NULL;
473: } else {
474: passphrase1 =
475: read_passphrase("Enter new passphrase (empty for no passphrase): ", 1);
476: passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
477:
478: /* Verify that they are the same. */
479: if (strcmp(passphrase1, passphrase2) != 0) {
480: memset(passphrase1, 0, strlen(passphrase1));
481: memset(passphrase2, 0, strlen(passphrase2));
482: xfree(passphrase1);
483: xfree(passphrase2);
484: printf("Pass phrases do not match. Try again.\n");
485: exit(1);
486: }
487: /* Destroy the other copy. */
488: memset(passphrase2, 0, strlen(passphrase2));
489: xfree(passphrase2);
490: }
491:
492: /* Save the file using the new passphrase. */
1.19 markus 493: if (!save_private_key(identity_file, passphrase1, private, comment)) {
1.12 markus 494: printf("Saving the key failed: %s: %s.\n",
495: identity_file, strerror(errno));
496: memset(passphrase1, 0, strlen(passphrase1));
497: xfree(passphrase1);
1.19 markus 498: key_free(private);
1.12 markus 499: xfree(comment);
500: exit(1);
501: }
502: /* Destroy the passphrase and the copy of the key in memory. */
503: memset(passphrase1, 0, strlen(passphrase1));
504: xfree(passphrase1);
1.19 markus 505: key_free(private); /* Destroys contents */
1.12 markus 506: xfree(comment);
1.1 deraadt 507:
1.12 markus 508: printf("Your identification has been saved with the new passphrase.\n");
509: exit(0);
1.1 deraadt 510: }
511:
1.13 deraadt 512: /*
513: * Change the comment of a private key file.
514: */
1.2 provos 515: void
516: do_change_comment(struct passwd *pw)
1.1 deraadt 517: {
1.25.2.5! jason 518: char new_comment[1024], *comment, *passphrase;
! 519: Key *private, *public;
1.12 markus 520: struct stat st;
521: FILE *f;
1.25.2.5! jason 522: int fd;
1.12 markus 523:
524: if (!have_identity)
525: ask_filename(pw, "Enter file in which the key is");
526: if (stat(identity_file, &st) < 0) {
527: perror(identity_file);
528: exit(1);
529: }
1.14 markus 530: /*
531: * Try to load the public key from the file the verify that it is
532: * readable and of the proper format.
533: */
1.25.2.4 jason 534: public = key_new(KEY_RSA1);
1.19 markus 535: if (!load_public_key(identity_file, public, NULL)) {
1.12 markus 536: printf("%s is not a valid key file.\n", identity_file);
1.25.2.4 jason 537: printf("Comments are only supported in RSA1 keys\n");
1.12 markus 538: exit(1);
539: }
1.14 markus 540:
1.25.2.4 jason 541: private = key_new(KEY_RSA1);
1.19 markus 542: if (load_private_key(identity_file, "", private, &comment))
1.12 markus 543: passphrase = xstrdup("");
544: else {
545: if (identity_passphrase)
546: passphrase = xstrdup(identity_passphrase);
547: else if (identity_new_passphrase)
548: passphrase = xstrdup(identity_new_passphrase);
549: else
550: passphrase = read_passphrase("Enter passphrase: ", 1);
551: /* Try to load using the passphrase. */
1.19 markus 552: if (!load_private_key(identity_file, passphrase, private, &comment)) {
1.12 markus 553: memset(passphrase, 0, strlen(passphrase));
554: xfree(passphrase);
555: printf("Bad passphrase.\n");
556: exit(1);
557: }
558: }
559: printf("Key now has comment '%s'\n", comment);
560:
561: if (identity_comment) {
562: strlcpy(new_comment, identity_comment, sizeof(new_comment));
563: } else {
564: printf("Enter new comment: ");
565: fflush(stdout);
566: if (!fgets(new_comment, sizeof(new_comment), stdin)) {
567: memset(passphrase, 0, strlen(passphrase));
1.19 markus 568: key_free(private);
1.12 markus 569: exit(1);
570: }
571: if (strchr(new_comment, '\n'))
572: *strchr(new_comment, '\n') = 0;
573: }
574:
575: /* Save the file using the new passphrase. */
1.19 markus 576: if (!save_private_key(identity_file, passphrase, private, new_comment)) {
1.12 markus 577: printf("Saving the key failed: %s: %s.\n",
578: identity_file, strerror(errno));
579: memset(passphrase, 0, strlen(passphrase));
580: xfree(passphrase);
1.19 markus 581: key_free(private);
1.12 markus 582: xfree(comment);
583: exit(1);
584: }
585: memset(passphrase, 0, strlen(passphrase));
586: xfree(passphrase);
1.19 markus 587: key_free(private);
1.12 markus 588:
589: strlcat(identity_file, ".pub", sizeof(identity_file));
1.25.2.5! jason 590: fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
! 591: if (fd == -1) {
1.12 markus 592: printf("Could not save your public key in %s\n", identity_file);
593: exit(1);
594: }
1.25.2.5! jason 595: f = fdopen(fd, "w");
! 596: if (f == NULL) {
! 597: printf("fdopen %s failed", identity_file);
! 598: exit(1);
! 599: }
1.19 markus 600: if (!key_write(public, f))
601: fprintf(stderr, "write key failed");
602: key_free(public);
603: fprintf(f, " %s\n", new_comment);
1.12 markus 604: fclose(f);
1.1 deraadt 605:
1.12 markus 606: xfree(comment);
1.1 deraadt 607:
1.12 markus 608: printf("The comment in your key file has been changed.\n");
609: exit(0);
1.1 deraadt 610: }
611:
1.10 markus 612: void
613: usage(void)
614: {
1.25.2.5! jason 615: printf("Usage: %s [-lpqxXyc] [-t type] [-b bits] [-f file] [-C comment] "
! 616: "[-N new-pass] [-P pass]\n", __progname);
1.12 markus 617: exit(1);
1.10 markus 618: }
619:
1.13 deraadt 620: /*
621: * Main program for key management.
622: */
1.2 provos 623: int
624: main(int ac, char **av)
1.1 deraadt 625: {
1.12 markus 626: char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
1.25.2.5! jason 627: Key *private, *public;
1.12 markus 628: struct passwd *pw;
1.25.2.5! jason 629: int opt, type, fd;
1.12 markus 630: struct stat st;
631: FILE *f;
1.25.2.4 jason 632:
1.12 markus 633: extern int optind;
634: extern char *optarg;
635:
1.25.2.1 jason 636: SSLeay_add_all_algorithms();
1.19 markus 637:
1.14 markus 638: /* we need this for the home * directory. */
1.12 markus 639: pw = getpwuid(getuid());
640: if (!pw) {
641: printf("You don't exist, go away!\n");
642: exit(1);
643: }
1.19 markus 644: if (gethostname(hostname, sizeof(hostname)) < 0) {
645: perror("gethostname");
646: exit(1);
647: }
1.14 markus 648:
1.25.2.5! jason 649: while ((opt = getopt(ac, av, "dqpclBRxXyb:f:t:P:N:C:")) != -1) {
1.12 markus 650: switch (opt) {
651: case 'b':
652: bits = atoi(optarg);
653: if (bits < 512 || bits > 32768) {
654: printf("Bits has bad value.\n");
655: exit(1);
656: }
657: break;
658:
659: case 'l':
660: print_fingerprint = 1;
661: break;
662:
1.25.2.5! jason 663: case 'B':
! 664: print_bubblebabble = 1;
! 665: break;
! 666:
1.12 markus 667: case 'p':
668: change_passphrase = 1;
669: break;
670:
671: case 'c':
672: change_comment = 1;
673: break;
674:
675: case 'f':
676: strlcpy(identity_file, optarg, sizeof(identity_file));
677: have_identity = 1;
678: break;
679:
680: case 'P':
681: identity_passphrase = optarg;
682: break;
683:
684: case 'N':
685: identity_new_passphrase = optarg;
686: break;
687:
688: case 'C':
689: identity_comment = optarg;
690: break;
691:
692: case 'q':
693: quiet = 1;
1.20 deraadt 694: break;
695:
696: case 'R':
1.25.2.4 jason 697: /* unused */
698: exit(0);
1.12 markus 699: break;
700:
1.19 markus 701: case 'x':
702: convert_to_ssh2 = 1;
703: break;
704:
705: case 'X':
706: convert_from_ssh2 = 1;
707: break;
708:
709: case 'y':
710: print_public = 1;
711: break;
712:
713: case 'd':
1.25.2.4 jason 714: key_type_name = "dsa";
715: break;
716:
717: case 't':
718: key_type_name = optarg;
1.19 markus 719: break;
720:
1.12 markus 721: case '?':
722: default:
723: usage();
724: }
725: }
726: if (optind < ac) {
727: printf("Too many arguments.\n");
728: usage();
729: }
730: if (change_passphrase && change_comment) {
731: printf("Can only have one of -p and -c.\n");
732: usage();
733: }
1.25.2.5! jason 734: if (print_fingerprint || print_bubblebabble)
1.12 markus 735: do_fingerprint(pw);
736: if (change_passphrase)
737: do_change_passphrase(pw);
738: if (change_comment)
739: do_change_comment(pw);
1.19 markus 740: if (convert_to_ssh2)
741: do_convert_to_ssh2(pw);
742: if (convert_from_ssh2)
743: do_convert_from_ssh2(pw);
744: if (print_public)
745: do_print_public(pw);
1.12 markus 746:
747: arc4random_stir();
748:
1.25.2.4 jason 749: type = key_type_from_name(key_type_name);
750: if (type == KEY_UNSPEC) {
751: fprintf(stderr, "unknown key type %s\n", key_type_name);
752: exit(1);
753: }
754: if (!quiet)
755: printf("Generating public/private %s key pair.\n", key_type_name);
756: private = key_generate(type, bits);
757: if (private == NULL) {
758: fprintf(stderr, "key_generate failed");
759: exit(1);
1.19 markus 760: }
1.25.2.4 jason 761: public = key_from_private(private);
1.12 markus 762:
763: if (!have_identity)
764: ask_filename(pw, "Enter file in which to save the key");
765:
766: /* Create ~/.ssh directory if it doesn\'t already exist. */
1.25.2.4 jason 767: snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR);
1.12 markus 768: if (strstr(identity_file, dotsshdir) != NULL &&
769: stat(dotsshdir, &st) < 0) {
1.25.2.2 jason 770: if (mkdir(dotsshdir, 0700) < 0)
1.12 markus 771: error("Could not create directory '%s'.", dotsshdir);
772: else if (!quiet)
773: printf("Created directory '%s'.\n", dotsshdir);
774: }
775: /* If the file already exists, ask the user to confirm. */
776: if (stat(identity_file, &st) >= 0) {
777: char yesno[3];
778: printf("%s already exists.\n", identity_file);
779: printf("Overwrite (y/n)? ");
780: fflush(stdout);
781: if (fgets(yesno, sizeof(yesno), stdin) == NULL)
782: exit(1);
783: if (yesno[0] != 'y' && yesno[0] != 'Y')
784: exit(1);
785: }
786: /* Ask for a passphrase (twice). */
787: if (identity_passphrase)
788: passphrase1 = xstrdup(identity_passphrase);
789: else if (identity_new_passphrase)
790: passphrase1 = xstrdup(identity_new_passphrase);
791: else {
792: passphrase_again:
793: passphrase1 =
794: read_passphrase("Enter passphrase (empty for no passphrase): ", 1);
795: passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
796: if (strcmp(passphrase1, passphrase2) != 0) {
797: /* The passphrases do not match. Clear them and retry. */
798: memset(passphrase1, 0, strlen(passphrase1));
799: memset(passphrase2, 0, strlen(passphrase2));
800: xfree(passphrase1);
801: xfree(passphrase2);
802: printf("Passphrases do not match. Try again.\n");
803: goto passphrase_again;
804: }
805: /* Clear the other copy of the passphrase. */
806: memset(passphrase2, 0, strlen(passphrase2));
807: xfree(passphrase2);
808: }
809:
810: if (identity_comment) {
811: strlcpy(comment, identity_comment, sizeof(comment));
812: } else {
1.18 markus 813: /* Create default commend field for the passphrase. */
1.12 markus 814: snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
815: }
816:
817: /* Save the key with the given passphrase and comment. */
1.19 markus 818: if (!save_private_key(identity_file, passphrase1, private, comment)) {
1.12 markus 819: printf("Saving the key failed: %s: %s.\n",
1.19 markus 820: identity_file, strerror(errno));
1.12 markus 821: memset(passphrase1, 0, strlen(passphrase1));
822: xfree(passphrase1);
823: exit(1);
824: }
825: /* Clear the passphrase. */
826: memset(passphrase1, 0, strlen(passphrase1));
827: xfree(passphrase1);
828:
829: /* Clear the private key and the random number generator. */
1.25.2.4 jason 830: key_free(private);
1.12 markus 831: arc4random_stir();
832:
833: if (!quiet)
834: printf("Your identification has been saved in %s.\n", identity_file);
835:
836: strlcat(identity_file, ".pub", sizeof(identity_file));
1.25.2.5! jason 837: fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
! 838: if (fd == -1) {
1.12 markus 839: printf("Could not save your public key in %s\n", identity_file);
840: exit(1);
841: }
1.25.2.5! jason 842: f = fdopen(fd, "w");
! 843: if (f == NULL) {
! 844: printf("fdopen %s failed", identity_file);
! 845: exit(1);
! 846: }
1.19 markus 847: if (!key_write(public, f))
848: fprintf(stderr, "write key failed");
849: fprintf(f, " %s\n", comment);
1.12 markus 850: fclose(f);
851:
852: if (!quiet) {
1.25.2.5! jason 853: char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
1.19 markus 854: printf("Your public key has been saved in %s.\n",
855: identity_file);
1.12 markus 856: printf("The key fingerprint is:\n");
1.25.2.5! jason 857: printf("%s %s\n", fp, comment);
! 858: xfree(fp);
1.12 markus 859: }
1.19 markus 860:
861: key_free(public);
1.12 markus 862: exit(0);
1.1 deraadt 863: }