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