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