xref: /freebsd/crypto/openssh/ssh-keygen.c (revision aa64588d28258aef88cc33b8043112e8856948d0)
1 /* $OpenBSD: ssh-keygen.c,v 1.185 2010/03/15 19:40:02 stevesk Exp $ */
2 /*
3  * Author: Tatu Ylonen <ylo@cs.hut.fi>
4  * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5  *                    All rights reserved
6  * Identity and host key generation and maintenance.
7  *
8  * As far as I am concerned, the code I have written for this software
9  * can be used freely for any purpose.  Any derived versions of this
10  * software must be clearly marked as such, and if the derived work is
11  * incompatible with the protocol description in the RFC file, it must be
12  * called by a name other than "ssh" or "Secure Shell".
13  */
14 
15 #include "includes.h"
16 
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <sys/stat.h>
20 #include <sys/param.h>
21 
22 #include <openssl/evp.h>
23 #include <openssl/pem.h>
24 #include "openbsd-compat/openssl-compat.h"
25 
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <netdb.h>
29 #ifdef HAVE_PATHS_H
30 # include <paths.h>
31 #endif
32 #include <pwd.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 
39 #include "xmalloc.h"
40 #include "key.h"
41 #include "rsa.h"
42 #include "authfile.h"
43 #include "uuencode.h"
44 #include "buffer.h"
45 #include "pathnames.h"
46 #include "log.h"
47 #include "misc.h"
48 #include "match.h"
49 #include "hostfile.h"
50 #include "dns.h"
51 #include "ssh2.h"
52 
53 #ifdef ENABLE_PKCS11
54 #include "ssh-pkcs11.h"
55 #endif
56 
57 /* Number of bits in the RSA/DSA key.  This value can be set on the command line. */
58 #define DEFAULT_BITS		2048
59 #define DEFAULT_BITS_DSA	1024
60 u_int32_t bits = 0;
61 
62 /*
63  * Flag indicating that we just want to change the passphrase.  This can be
64  * set on the command line.
65  */
66 int change_passphrase = 0;
67 
68 /*
69  * Flag indicating that we just want to change the comment.  This can be set
70  * on the command line.
71  */
72 int change_comment = 0;
73 
74 int quiet = 0;
75 
76 int log_level = SYSLOG_LEVEL_INFO;
77 
78 /* Flag indicating that we want to hash a known_hosts file */
79 int hash_hosts = 0;
80 /* Flag indicating that we want lookup a host in known_hosts file */
81 int find_host = 0;
82 /* Flag indicating that we want to delete a host from a known_hosts file */
83 int delete_host = 0;
84 
85 /* Flag indicating that we want to show the contents of a certificate */
86 int show_cert = 0;
87 
88 /* Flag indicating that we just want to see the key fingerprint */
89 int print_fingerprint = 0;
90 int print_bubblebabble = 0;
91 
92 /* The identity file name, given on the command line or entered by the user. */
93 char identity_file[1024];
94 int have_identity = 0;
95 
96 /* This is set to the passphrase if given on the command line. */
97 char *identity_passphrase = NULL;
98 
99 /* This is set to the new passphrase if given on the command line. */
100 char *identity_new_passphrase = NULL;
101 
102 /* This is set to the new comment if given on the command line. */
103 char *identity_comment = NULL;
104 
105 /* Path to CA key when certifying keys. */
106 char *ca_key_path = NULL;
107 
108 /* Key type when certifying */
109 u_int cert_key_type = SSH2_CERT_TYPE_USER;
110 
111 /* "key ID" of signed key */
112 char *cert_key_id = NULL;
113 
114 /* Comma-separated list of principal names for certifying keys */
115 char *cert_principals = NULL;
116 
117 /* Validity period for certificates */
118 u_int64_t cert_valid_from = 0;
119 u_int64_t cert_valid_to = ~0ULL;
120 
121 /* Certificate constraints */
122 #define CONSTRAINT_X_FWD	(1)
123 #define CONSTRAINT_AGENT_FWD	(1<<1)
124 #define CONSTRAINT_PORT_FWD	(1<<2)
125 #define CONSTRAINT_PTY		(1<<3)
126 #define CONSTRAINT_USER_RC	(1<<4)
127 #define CONSTRAINT_DEFAULT	(CONSTRAINT_X_FWD|CONSTRAINT_AGENT_FWD| \
128 				CONSTRAINT_PORT_FWD|CONSTRAINT_PTY| \
129 				CONSTRAINT_USER_RC)
130 u_int32_t constraint_flags = CONSTRAINT_DEFAULT;
131 char *constraint_command = NULL;
132 char *constraint_src_addr = NULL;
133 
134 /* Dump public key file in format used by real and the original SSH 2 */
135 int convert_to_ssh2 = 0;
136 int convert_from_ssh2 = 0;
137 int print_public = 0;
138 int print_generic = 0;
139 
140 char *key_type_name = NULL;
141 
142 /* argv0 */
143 extern char *__progname;
144 
145 char hostname[MAXHOSTNAMELEN];
146 
147 /* moduli.c */
148 int gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *);
149 int prime_test(FILE *, FILE *, u_int32_t, u_int32_t);
150 
151 static void
152 ask_filename(struct passwd *pw, const char *prompt)
153 {
154 	char buf[1024];
155 	char *name = NULL;
156 
157 	if (key_type_name == NULL)
158 		name = _PATH_SSH_CLIENT_ID_RSA;
159 	else {
160 		switch (key_type_from_name(key_type_name)) {
161 		case KEY_RSA1:
162 			name = _PATH_SSH_CLIENT_IDENTITY;
163 			break;
164 		case KEY_DSA:
165 			name = _PATH_SSH_CLIENT_ID_DSA;
166 			break;
167 		case KEY_RSA:
168 			name = _PATH_SSH_CLIENT_ID_RSA;
169 			break;
170 		default:
171 			fprintf(stderr, "bad key type\n");
172 			exit(1);
173 			break;
174 		}
175 	}
176 	snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name);
177 	fprintf(stderr, "%s (%s): ", prompt, identity_file);
178 	if (fgets(buf, sizeof(buf), stdin) == NULL)
179 		exit(1);
180 	buf[strcspn(buf, "\n")] = '\0';
181 	if (strcmp(buf, "") != 0)
182 		strlcpy(identity_file, buf, sizeof(identity_file));
183 	have_identity = 1;
184 }
185 
186 static Key *
187 load_identity(char *filename)
188 {
189 	char *pass;
190 	Key *prv;
191 
192 	prv = key_load_private(filename, "", NULL);
193 	if (prv == NULL) {
194 		if (identity_passphrase)
195 			pass = xstrdup(identity_passphrase);
196 		else
197 			pass = read_passphrase("Enter passphrase: ",
198 			    RP_ALLOW_STDIN);
199 		prv = key_load_private(filename, pass, NULL);
200 		memset(pass, 0, strlen(pass));
201 		xfree(pass);
202 	}
203 	return prv;
204 }
205 
206 #define SSH_COM_PUBLIC_BEGIN		"---- BEGIN SSH2 PUBLIC KEY ----"
207 #define SSH_COM_PUBLIC_END		"---- END SSH2 PUBLIC KEY ----"
208 #define SSH_COM_PRIVATE_BEGIN		"---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
209 #define	SSH_COM_PRIVATE_KEY_MAGIC	0x3f6ff9eb
210 
211 static void
212 do_convert_to_ssh2(struct passwd *pw)
213 {
214 	Key *k;
215 	u_int len;
216 	u_char *blob;
217 	char comment[61];
218 	struct stat st;
219 
220 	if (!have_identity)
221 		ask_filename(pw, "Enter file in which the key is");
222 	if (stat(identity_file, &st) < 0) {
223 		perror(identity_file);
224 		exit(1);
225 	}
226 	if ((k = key_load_public(identity_file, NULL)) == NULL) {
227 		if ((k = load_identity(identity_file)) == NULL) {
228 			fprintf(stderr, "load failed\n");
229 			exit(1);
230 		}
231 	}
232 	if (k->type == KEY_RSA1) {
233 		fprintf(stderr, "version 1 keys are not supported\n");
234 		exit(1);
235 	}
236 	if (key_to_blob(k, &blob, &len) <= 0) {
237 		fprintf(stderr, "key_to_blob failed\n");
238 		exit(1);
239 	}
240 	/* Comment + surrounds must fit into 72 chars (RFC 4716 sec 3.3) */
241 	snprintf(comment, sizeof(comment),
242 	    "%u-bit %s, converted by %s@%s from OpenSSH",
243 	    key_size(k), key_type(k),
244 	    pw->pw_name, hostname);
245 
246 	fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
247 	fprintf(stdout, "Comment: \"%s\"\n", comment);
248 	dump_base64(stdout, blob, len);
249 	fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
250 	key_free(k);
251 	xfree(blob);
252 	exit(0);
253 }
254 
255 static void
256 buffer_get_bignum_bits(Buffer *b, BIGNUM *value)
257 {
258 	u_int bignum_bits = buffer_get_int(b);
259 	u_int bytes = (bignum_bits + 7) / 8;
260 
261 	if (buffer_len(b) < bytes)
262 		fatal("buffer_get_bignum_bits: input buffer too small: "
263 		    "need %d have %d", bytes, buffer_len(b));
264 	if (BN_bin2bn(buffer_ptr(b), bytes, value) == NULL)
265 		fatal("buffer_get_bignum_bits: BN_bin2bn failed");
266 	buffer_consume(b, bytes);
267 }
268 
269 static Key *
270 do_convert_private_ssh2_from_blob(u_char *blob, u_int blen)
271 {
272 	Buffer b;
273 	Key *key = NULL;
274 	char *type, *cipher;
275 	u_char *sig, data[] = "abcde12345";
276 	int magic, rlen, ktype, i1, i2, i3, i4;
277 	u_int slen;
278 	u_long e;
279 
280 	buffer_init(&b);
281 	buffer_append(&b, blob, blen);
282 
283 	magic = buffer_get_int(&b);
284 	if (magic != SSH_COM_PRIVATE_KEY_MAGIC) {
285 		error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC);
286 		buffer_free(&b);
287 		return NULL;
288 	}
289 	i1 = buffer_get_int(&b);
290 	type   = buffer_get_string(&b, NULL);
291 	cipher = buffer_get_string(&b, NULL);
292 	i2 = buffer_get_int(&b);
293 	i3 = buffer_get_int(&b);
294 	i4 = buffer_get_int(&b);
295 	debug("ignore (%d %d %d %d)", i1, i2, i3, i4);
296 	if (strcmp(cipher, "none") != 0) {
297 		error("unsupported cipher %s", cipher);
298 		xfree(cipher);
299 		buffer_free(&b);
300 		xfree(type);
301 		return NULL;
302 	}
303 	xfree(cipher);
304 
305 	if (strstr(type, "dsa")) {
306 		ktype = KEY_DSA;
307 	} else if (strstr(type, "rsa")) {
308 		ktype = KEY_RSA;
309 	} else {
310 		buffer_free(&b);
311 		xfree(type);
312 		return NULL;
313 	}
314 	key = key_new_private(ktype);
315 	xfree(type);
316 
317 	switch (key->type) {
318 	case KEY_DSA:
319 		buffer_get_bignum_bits(&b, key->dsa->p);
320 		buffer_get_bignum_bits(&b, key->dsa->g);
321 		buffer_get_bignum_bits(&b, key->dsa->q);
322 		buffer_get_bignum_bits(&b, key->dsa->pub_key);
323 		buffer_get_bignum_bits(&b, key->dsa->priv_key);
324 		break;
325 	case KEY_RSA:
326 		e = buffer_get_char(&b);
327 		debug("e %lx", e);
328 		if (e < 30) {
329 			e <<= 8;
330 			e += buffer_get_char(&b);
331 			debug("e %lx", e);
332 			e <<= 8;
333 			e += buffer_get_char(&b);
334 			debug("e %lx", e);
335 		}
336 		if (!BN_set_word(key->rsa->e, e)) {
337 			buffer_free(&b);
338 			key_free(key);
339 			return NULL;
340 		}
341 		buffer_get_bignum_bits(&b, key->rsa->d);
342 		buffer_get_bignum_bits(&b, key->rsa->n);
343 		buffer_get_bignum_bits(&b, key->rsa->iqmp);
344 		buffer_get_bignum_bits(&b, key->rsa->q);
345 		buffer_get_bignum_bits(&b, key->rsa->p);
346 		rsa_generate_additional_parameters(key->rsa);
347 		break;
348 	}
349 	rlen = buffer_len(&b);
350 	if (rlen != 0)
351 		error("do_convert_private_ssh2_from_blob: "
352 		    "remaining bytes in key blob %d", rlen);
353 	buffer_free(&b);
354 
355 	/* try the key */
356 	key_sign(key, &sig, &slen, data, sizeof(data));
357 	key_verify(key, sig, slen, data, sizeof(data));
358 	xfree(sig);
359 	return key;
360 }
361 
362 static int
363 get_line(FILE *fp, char *line, size_t len)
364 {
365 	int c;
366 	size_t pos = 0;
367 
368 	line[0] = '\0';
369 	while ((c = fgetc(fp)) != EOF) {
370 		if (pos >= len - 1) {
371 			fprintf(stderr, "input line too long.\n");
372 			exit(1);
373 		}
374 		switch (c) {
375 		case '\r':
376 			c = fgetc(fp);
377 			if (c != EOF && c != '\n' && ungetc(c, fp) == EOF) {
378 				fprintf(stderr, "unget: %s\n", strerror(errno));
379 				exit(1);
380 			}
381 			return pos;
382 		case '\n':
383 			return pos;
384 		}
385 		line[pos++] = c;
386 		line[pos] = '\0';
387 	}
388 	/* We reached EOF */
389 	return -1;
390 }
391 
392 static void
393 do_convert_from_ssh2(struct passwd *pw)
394 {
395 	Key *k;
396 	int blen;
397 	u_int len;
398 	char line[1024];
399 	u_char blob[8096];
400 	char encoded[8096];
401 	struct stat st;
402 	int escaped = 0, private = 0, ok;
403 	FILE *fp;
404 
405 	if (!have_identity)
406 		ask_filename(pw, "Enter file in which the key is");
407 	if (stat(identity_file, &st) < 0) {
408 		perror(identity_file);
409 		exit(1);
410 	}
411 	fp = fopen(identity_file, "r");
412 	if (fp == NULL) {
413 		perror(identity_file);
414 		exit(1);
415 	}
416 	encoded[0] = '\0';
417 	while ((blen = get_line(fp, line, sizeof(line))) != -1) {
418 		if (line[blen - 1] == '\\')
419 			escaped++;
420 		if (strncmp(line, "----", 4) == 0 ||
421 		    strstr(line, ": ") != NULL) {
422 			if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL)
423 				private = 1;
424 			if (strstr(line, " END ") != NULL) {
425 				break;
426 			}
427 			/* fprintf(stderr, "ignore: %s", line); */
428 			continue;
429 		}
430 		if (escaped) {
431 			escaped--;
432 			/* fprintf(stderr, "escaped: %s", line); */
433 			continue;
434 		}
435 		strlcat(encoded, line, sizeof(encoded));
436 	}
437 	len = strlen(encoded);
438 	if (((len % 4) == 3) &&
439 	    (encoded[len-1] == '=') &&
440 	    (encoded[len-2] == '=') &&
441 	    (encoded[len-3] == '='))
442 		encoded[len-3] = '\0';
443 	blen = uudecode(encoded, blob, sizeof(blob));
444 	if (blen < 0) {
445 		fprintf(stderr, "uudecode failed.\n");
446 		exit(1);
447 	}
448 	k = private ?
449 	    do_convert_private_ssh2_from_blob(blob, blen) :
450 	    key_from_blob(blob, blen);
451 	if (k == NULL) {
452 		fprintf(stderr, "decode blob failed.\n");
453 		exit(1);
454 	}
455 	ok = private ?
456 	    (k->type == KEY_DSA ?
457 		 PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) :
458 		 PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) :
459 	    key_write(k, stdout);
460 	if (!ok) {
461 		fprintf(stderr, "key write failed\n");
462 		exit(1);
463 	}
464 	key_free(k);
465 	if (!private)
466 		fprintf(stdout, "\n");
467 	fclose(fp);
468 	exit(0);
469 }
470 
471 static void
472 do_print_public(struct passwd *pw)
473 {
474 	Key *prv;
475 	struct stat st;
476 
477 	if (!have_identity)
478 		ask_filename(pw, "Enter file in which the key is");
479 	if (stat(identity_file, &st) < 0) {
480 		perror(identity_file);
481 		exit(1);
482 	}
483 	prv = load_identity(identity_file);
484 	if (prv == NULL) {
485 		fprintf(stderr, "load failed\n");
486 		exit(1);
487 	}
488 	if (!key_write(prv, stdout))
489 		fprintf(stderr, "key_write failed");
490 	key_free(prv);
491 	fprintf(stdout, "\n");
492 	exit(0);
493 }
494 
495 static void
496 do_download(struct passwd *pw, char *pkcs11provider)
497 {
498 #ifdef ENABLE_PKCS11
499 	Key **keys = NULL;
500 	int i, nkeys;
501 
502 	pkcs11_init(0);
503 	nkeys = pkcs11_add_provider(pkcs11provider, NULL, &keys);
504 	if (nkeys <= 0)
505 		fatal("cannot read public key from pkcs11");
506 	for (i = 0; i < nkeys; i++) {
507 		key_write(keys[i], stdout);
508 		key_free(keys[i]);
509 		fprintf(stdout, "\n");
510 	}
511 	xfree(keys);
512 	pkcs11_terminate();
513 	exit(0);
514 #else
515 	fatal("no pkcs11 support");
516 #endif /* ENABLE_PKCS11 */
517 }
518 
519 static void
520 do_fingerprint(struct passwd *pw)
521 {
522 	FILE *f;
523 	Key *public;
524 	char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra;
525 	int i, skip = 0, num = 0, invalid = 1;
526 	enum fp_rep rep;
527 	enum fp_type fptype;
528 	struct stat st;
529 
530 	fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
531 	rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
532 
533 	if (!have_identity)
534 		ask_filename(pw, "Enter file in which the key is");
535 	if (stat(identity_file, &st) < 0) {
536 		perror(identity_file);
537 		exit(1);
538 	}
539 	public = key_load_public(identity_file, &comment);
540 	if (public != NULL) {
541 		fp = key_fingerprint(public, fptype, rep);
542 		ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
543 		printf("%u %s %s (%s)\n", key_size(public), fp, comment,
544 		    key_type(public));
545 		if (log_level >= SYSLOG_LEVEL_VERBOSE)
546 			printf("%s\n", ra);
547 		key_free(public);
548 		xfree(comment);
549 		xfree(ra);
550 		xfree(fp);
551 		exit(0);
552 	}
553 	if (comment) {
554 		xfree(comment);
555 		comment = NULL;
556 	}
557 
558 	f = fopen(identity_file, "r");
559 	if (f != NULL) {
560 		while (fgets(line, sizeof(line), f)) {
561 			if ((cp = strchr(line, '\n')) == NULL) {
562 				error("line %d too long: %.40s...",
563 				    num + 1, line);
564 				skip = 1;
565 				continue;
566 			}
567 			num++;
568 			if (skip) {
569 				skip = 0;
570 				continue;
571 			}
572 			*cp = '\0';
573 
574 			/* Skip leading whitespace, empty and comment lines. */
575 			for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
576 				;
577 			if (!*cp || *cp == '\n' || *cp == '#')
578 				continue;
579 			i = strtol(cp, &ep, 10);
580 			if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
581 				int quoted = 0;
582 				comment = cp;
583 				for (; *cp && (quoted || (*cp != ' ' &&
584 				    *cp != '\t')); cp++) {
585 					if (*cp == '\\' && cp[1] == '"')
586 						cp++;	/* Skip both */
587 					else if (*cp == '"')
588 						quoted = !quoted;
589 				}
590 				if (!*cp)
591 					continue;
592 				*cp++ = '\0';
593 			}
594 			ep = cp;
595 			public = key_new(KEY_RSA1);
596 			if (key_read(public, &cp) != 1) {
597 				cp = ep;
598 				key_free(public);
599 				public = key_new(KEY_UNSPEC);
600 				if (key_read(public, &cp) != 1) {
601 					key_free(public);
602 					continue;
603 				}
604 			}
605 			comment = *cp ? cp : comment;
606 			fp = key_fingerprint(public, fptype, rep);
607 			ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
608 			printf("%u %s %s (%s)\n", key_size(public), fp,
609 			    comment ? comment : "no comment", key_type(public));
610 			if (log_level >= SYSLOG_LEVEL_VERBOSE)
611 				printf("%s\n", ra);
612 			xfree(ra);
613 			xfree(fp);
614 			key_free(public);
615 			invalid = 0;
616 		}
617 		fclose(f);
618 	}
619 	if (invalid) {
620 		printf("%s is not a public key file.\n", identity_file);
621 		exit(1);
622 	}
623 	exit(0);
624 }
625 
626 static void
627 printhost(FILE *f, const char *name, Key *public, int ca, int hash)
628 {
629 	if (print_fingerprint) {
630 		enum fp_rep rep;
631 		enum fp_type fptype;
632 		char *fp, *ra;
633 
634 		fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
635 		rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
636 		fp = key_fingerprint(public, fptype, rep);
637 		ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
638 		printf("%u %s %s (%s)\n", key_size(public), fp, name,
639 		    key_type(public));
640 		if (log_level >= SYSLOG_LEVEL_VERBOSE)
641 			printf("%s\n", ra);
642 		xfree(ra);
643 		xfree(fp);
644 	} else {
645 		if (hash && (name = host_hash(name, NULL, 0)) == NULL)
646 			fatal("hash_host failed");
647 		fprintf(f, "%s%s%s ", ca ? CA_MARKER : "", ca ? " " : "", name);
648 		if (!key_write(public, f))
649 			fatal("key_write failed");
650 		fprintf(f, "\n");
651 	}
652 }
653 
654 static void
655 do_known_hosts(struct passwd *pw, const char *name)
656 {
657 	FILE *in, *out = stdout;
658 	Key *pub;
659 	char *cp, *cp2, *kp, *kp2;
660 	char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN];
661 	int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0;
662 	int ca;
663 
664 	if (!have_identity) {
665 		cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
666 		if (strlcpy(identity_file, cp, sizeof(identity_file)) >=
667 		    sizeof(identity_file))
668 			fatal("Specified known hosts path too long");
669 		xfree(cp);
670 		have_identity = 1;
671 	}
672 	if ((in = fopen(identity_file, "r")) == NULL)
673 		fatal("fopen: %s", strerror(errno));
674 
675 	/*
676 	 * Find hosts goes to stdout, hash and deletions happen in-place
677 	 * A corner case is ssh-keygen -HF foo, which should go to stdout
678 	 */
679 	if (!find_host && (hash_hosts || delete_host)) {
680 		if (strlcpy(tmp, identity_file, sizeof(tmp)) >= sizeof(tmp) ||
681 		    strlcat(tmp, ".XXXXXXXXXX", sizeof(tmp)) >= sizeof(tmp) ||
682 		    strlcpy(old, identity_file, sizeof(old)) >= sizeof(old) ||
683 		    strlcat(old, ".old", sizeof(old)) >= sizeof(old))
684 			fatal("known_hosts path too long");
685 		umask(077);
686 		if ((c = mkstemp(tmp)) == -1)
687 			fatal("mkstemp: %s", strerror(errno));
688 		if ((out = fdopen(c, "w")) == NULL) {
689 			c = errno;
690 			unlink(tmp);
691 			fatal("fdopen: %s", strerror(c));
692 		}
693 		inplace = 1;
694 	}
695 
696 	while (fgets(line, sizeof(line), in)) {
697 		if ((cp = strchr(line, '\n')) == NULL) {
698 			error("line %d too long: %.40s...", num + 1, line);
699 			skip = 1;
700 			invalid = 1;
701 			continue;
702 		}
703 		num++;
704 		if (skip) {
705 			skip = 0;
706 			continue;
707 		}
708 		*cp = '\0';
709 
710 		/* Skip leading whitespace, empty and comment lines. */
711 		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
712 			;
713 		if (!*cp || *cp == '\n' || *cp == '#') {
714 			if (inplace)
715 				fprintf(out, "%s\n", cp);
716 			continue;
717 		}
718 		/* Check whether this is a CA key */
719 		if (strncasecmp(cp, CA_MARKER, sizeof(CA_MARKER) - 1) == 0 &&
720 		    (cp[sizeof(CA_MARKER) - 1] == ' ' ||
721 		    cp[sizeof(CA_MARKER) - 1] == '\t')) {
722 			ca = 1;
723 			cp += sizeof(CA_MARKER);
724 		} else
725 			ca = 0;
726 
727 		/* Find the end of the host name portion. */
728 		for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++)
729 			;
730 
731 		if (*kp == '\0' || *(kp + 1) == '\0') {
732 			error("line %d missing key: %.40s...",
733 			    num, line);
734 			invalid = 1;
735 			continue;
736 		}
737 		*kp++ = '\0';
738 		kp2 = kp;
739 
740 		pub = key_new(KEY_RSA1);
741 		if (key_read(pub, &kp) != 1) {
742 			kp = kp2;
743 			key_free(pub);
744 			pub = key_new(KEY_UNSPEC);
745 			if (key_read(pub, &kp) != 1) {
746 				error("line %d invalid key: %.40s...",
747 				    num, line);
748 				key_free(pub);
749 				invalid = 1;
750 				continue;
751 			}
752 		}
753 
754 		if (*cp == HASH_DELIM) {
755 			if (find_host || delete_host) {
756 				cp2 = host_hash(name, cp, strlen(cp));
757 				if (cp2 == NULL) {
758 					error("line %d: invalid hashed "
759 					    "name: %.64s...", num, line);
760 					invalid = 1;
761 					continue;
762 				}
763 				c = (strcmp(cp2, cp) == 0);
764 				if (find_host && c) {
765 					printf("# Host %s found: "
766 					    "line %d type %s%s\n", name,
767 					    num, key_type(pub),
768 					    ca ? " (CA key)" : "");
769 					printhost(out, cp, pub, ca, 0);
770 				}
771 				if (delete_host && !c && !ca)
772 					printhost(out, cp, pub, ca, 0);
773 			} else if (hash_hosts)
774 				printhost(out, cp, pub, ca, 0);
775 		} else {
776 			if (find_host || delete_host) {
777 				c = (match_hostname(name, cp,
778 				    strlen(cp)) == 1);
779 				if (find_host && c) {
780 					printf("# Host %s found: "
781 					    "line %d type %s%s\n", name,
782 					    num, key_type(pub),
783 					    ca ? " (CA key)" : "");
784 					printhost(out, name, pub,
785 					    ca, hash_hosts && !ca);
786 				}
787 				if (delete_host && !c && !ca)
788 					printhost(out, cp, pub, ca, 0);
789 			} else if (hash_hosts) {
790 				for (cp2 = strsep(&cp, ",");
791 				    cp2 != NULL && *cp2 != '\0';
792 				    cp2 = strsep(&cp, ",")) {
793 					if (ca) {
794 						fprintf(stderr, "Warning: "
795 						    "ignoring CA key for host: "
796 						    "%.64s\n", cp2);
797 						printhost(out, cp2, pub, ca, 0);
798 					} else if (strcspn(cp2, "*?!") !=
799 					    strlen(cp2)) {
800 						fprintf(stderr, "Warning: "
801 						    "ignoring host name with "
802 						    "metacharacters: %.64s\n",
803 						    cp2);
804 						printhost(out, cp2, pub, ca, 0);
805 					} else
806 						printhost(out, cp2, pub, ca, 1);
807 				}
808 				has_unhashed = 1;
809 			}
810 		}
811 		key_free(pub);
812 	}
813 	fclose(in);
814 
815 	if (invalid) {
816 		fprintf(stderr, "%s is not a valid known_hosts file.\n",
817 		    identity_file);
818 		if (inplace) {
819 			fprintf(stderr, "Not replacing existing known_hosts "
820 			    "file because of errors\n");
821 			fclose(out);
822 			unlink(tmp);
823 		}
824 		exit(1);
825 	}
826 
827 	if (inplace) {
828 		fclose(out);
829 
830 		/* Backup existing file */
831 		if (unlink(old) == -1 && errno != ENOENT)
832 			fatal("unlink %.100s: %s", old, strerror(errno));
833 		if (link(identity_file, old) == -1)
834 			fatal("link %.100s to %.100s: %s", identity_file, old,
835 			    strerror(errno));
836 		/* Move new one into place */
837 		if (rename(tmp, identity_file) == -1) {
838 			error("rename\"%s\" to \"%s\": %s", tmp, identity_file,
839 			    strerror(errno));
840 			unlink(tmp);
841 			unlink(old);
842 			exit(1);
843 		}
844 
845 		fprintf(stderr, "%s updated.\n", identity_file);
846 		fprintf(stderr, "Original contents retained as %s\n", old);
847 		if (has_unhashed) {
848 			fprintf(stderr, "WARNING: %s contains unhashed "
849 			    "entries\n", old);
850 			fprintf(stderr, "Delete this file to ensure privacy "
851 			    "of hostnames\n");
852 		}
853 	}
854 
855 	exit(0);
856 }
857 
858 /*
859  * Perform changing a passphrase.  The argument is the passwd structure
860  * for the current user.
861  */
862 static void
863 do_change_passphrase(struct passwd *pw)
864 {
865 	char *comment;
866 	char *old_passphrase, *passphrase1, *passphrase2;
867 	struct stat st;
868 	Key *private;
869 
870 	if (!have_identity)
871 		ask_filename(pw, "Enter file in which the key is");
872 	if (stat(identity_file, &st) < 0) {
873 		perror(identity_file);
874 		exit(1);
875 	}
876 	/* Try to load the file with empty passphrase. */
877 	private = key_load_private(identity_file, "", &comment);
878 	if (private == NULL) {
879 		if (identity_passphrase)
880 			old_passphrase = xstrdup(identity_passphrase);
881 		else
882 			old_passphrase =
883 			    read_passphrase("Enter old passphrase: ",
884 			    RP_ALLOW_STDIN);
885 		private = key_load_private(identity_file, old_passphrase,
886 		    &comment);
887 		memset(old_passphrase, 0, strlen(old_passphrase));
888 		xfree(old_passphrase);
889 		if (private == NULL) {
890 			printf("Bad passphrase.\n");
891 			exit(1);
892 		}
893 	}
894 	printf("Key has comment '%s'\n", comment);
895 
896 	/* Ask the new passphrase (twice). */
897 	if (identity_new_passphrase) {
898 		passphrase1 = xstrdup(identity_new_passphrase);
899 		passphrase2 = NULL;
900 	} else {
901 		passphrase1 =
902 			read_passphrase("Enter new passphrase (empty for no "
903 			    "passphrase): ", RP_ALLOW_STDIN);
904 		passphrase2 = read_passphrase("Enter same passphrase again: ",
905 		    RP_ALLOW_STDIN);
906 
907 		/* Verify that they are the same. */
908 		if (strcmp(passphrase1, passphrase2) != 0) {
909 			memset(passphrase1, 0, strlen(passphrase1));
910 			memset(passphrase2, 0, strlen(passphrase2));
911 			xfree(passphrase1);
912 			xfree(passphrase2);
913 			printf("Pass phrases do not match.  Try again.\n");
914 			exit(1);
915 		}
916 		/* Destroy the other copy. */
917 		memset(passphrase2, 0, strlen(passphrase2));
918 		xfree(passphrase2);
919 	}
920 
921 	/* Save the file using the new passphrase. */
922 	if (!key_save_private(private, identity_file, passphrase1, comment)) {
923 		printf("Saving the key failed: %s.\n", identity_file);
924 		memset(passphrase1, 0, strlen(passphrase1));
925 		xfree(passphrase1);
926 		key_free(private);
927 		xfree(comment);
928 		exit(1);
929 	}
930 	/* Destroy the passphrase and the copy of the key in memory. */
931 	memset(passphrase1, 0, strlen(passphrase1));
932 	xfree(passphrase1);
933 	key_free(private);		 /* Destroys contents */
934 	xfree(comment);
935 
936 	printf("Your identification has been saved with the new passphrase.\n");
937 	exit(0);
938 }
939 
940 /*
941  * Print the SSHFP RR.
942  */
943 static int
944 do_print_resource_record(struct passwd *pw, char *fname, char *hname)
945 {
946 	Key *public;
947 	char *comment = NULL;
948 	struct stat st;
949 
950 	if (fname == NULL)
951 		ask_filename(pw, "Enter file in which the key is");
952 	if (stat(fname, &st) < 0) {
953 		if (errno == ENOENT)
954 			return 0;
955 		perror(fname);
956 		exit(1);
957 	}
958 	public = key_load_public(fname, &comment);
959 	if (public != NULL) {
960 		export_dns_rr(hname, public, stdout, print_generic);
961 		key_free(public);
962 		xfree(comment);
963 		return 1;
964 	}
965 	if (comment)
966 		xfree(comment);
967 
968 	printf("failed to read v2 public key from %s.\n", fname);
969 	exit(1);
970 }
971 
972 /*
973  * Change the comment of a private key file.
974  */
975 static void
976 do_change_comment(struct passwd *pw)
977 {
978 	char new_comment[1024], *comment, *passphrase;
979 	Key *private;
980 	Key *public;
981 	struct stat st;
982 	FILE *f;
983 	int fd;
984 
985 	if (!have_identity)
986 		ask_filename(pw, "Enter file in which the key is");
987 	if (stat(identity_file, &st) < 0) {
988 		perror(identity_file);
989 		exit(1);
990 	}
991 	private = key_load_private(identity_file, "", &comment);
992 	if (private == NULL) {
993 		if (identity_passphrase)
994 			passphrase = xstrdup(identity_passphrase);
995 		else if (identity_new_passphrase)
996 			passphrase = xstrdup(identity_new_passphrase);
997 		else
998 			passphrase = read_passphrase("Enter passphrase: ",
999 			    RP_ALLOW_STDIN);
1000 		/* Try to load using the passphrase. */
1001 		private = key_load_private(identity_file, passphrase, &comment);
1002 		if (private == NULL) {
1003 			memset(passphrase, 0, strlen(passphrase));
1004 			xfree(passphrase);
1005 			printf("Bad passphrase.\n");
1006 			exit(1);
1007 		}
1008 	} else {
1009 		passphrase = xstrdup("");
1010 	}
1011 	if (private->type != KEY_RSA1) {
1012 		fprintf(stderr, "Comments are only supported for RSA1 keys.\n");
1013 		key_free(private);
1014 		exit(1);
1015 	}
1016 	printf("Key now has comment '%s'\n", comment);
1017 
1018 	if (identity_comment) {
1019 		strlcpy(new_comment, identity_comment, sizeof(new_comment));
1020 	} else {
1021 		printf("Enter new comment: ");
1022 		fflush(stdout);
1023 		if (!fgets(new_comment, sizeof(new_comment), stdin)) {
1024 			memset(passphrase, 0, strlen(passphrase));
1025 			key_free(private);
1026 			exit(1);
1027 		}
1028 		new_comment[strcspn(new_comment, "\n")] = '\0';
1029 	}
1030 
1031 	/* Save the file using the new passphrase. */
1032 	if (!key_save_private(private, identity_file, passphrase, new_comment)) {
1033 		printf("Saving the key failed: %s.\n", identity_file);
1034 		memset(passphrase, 0, strlen(passphrase));
1035 		xfree(passphrase);
1036 		key_free(private);
1037 		xfree(comment);
1038 		exit(1);
1039 	}
1040 	memset(passphrase, 0, strlen(passphrase));
1041 	xfree(passphrase);
1042 	public = key_from_private(private);
1043 	key_free(private);
1044 
1045 	strlcat(identity_file, ".pub", sizeof(identity_file));
1046 	fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1047 	if (fd == -1) {
1048 		printf("Could not save your public key in %s\n", identity_file);
1049 		exit(1);
1050 	}
1051 	f = fdopen(fd, "w");
1052 	if (f == NULL) {
1053 		printf("fdopen %s failed\n", identity_file);
1054 		exit(1);
1055 	}
1056 	if (!key_write(public, f))
1057 		fprintf(stderr, "write key failed\n");
1058 	key_free(public);
1059 	fprintf(f, " %s\n", new_comment);
1060 	fclose(f);
1061 
1062 	xfree(comment);
1063 
1064 	printf("The comment in your key file has been changed.\n");
1065 	exit(0);
1066 }
1067 
1068 static const char *
1069 fmt_validity(u_int64_t valid_from, u_int64_t valid_to)
1070 {
1071 	char from[32], to[32];
1072 	static char ret[64];
1073 	time_t tt;
1074 	struct tm *tm;
1075 
1076 	*from = *to = '\0';
1077 	if (valid_from == 0 && valid_to == 0xffffffffffffffffULL)
1078 		return "forever";
1079 
1080 	if (valid_from != 0) {
1081 		/* XXX revisit INT_MAX in 2038 :) */
1082 		tt = valid_from > INT_MAX ? INT_MAX : valid_from;
1083 		tm = localtime(&tt);
1084 		strftime(from, sizeof(from), "%Y-%m-%dT%H:%M:%S", tm);
1085 	}
1086 	if (valid_to != 0xffffffffffffffffULL) {
1087 		/* XXX revisit INT_MAX in 2038 :) */
1088 		tt = valid_to > INT_MAX ? INT_MAX : valid_to;
1089 		tm = localtime(&tt);
1090 		strftime(to, sizeof(to), "%Y-%m-%dT%H:%M:%S", tm);
1091 	}
1092 
1093 	if (valid_from == 0) {
1094 		snprintf(ret, sizeof(ret), "before %s", to);
1095 		return ret;
1096 	}
1097 	if (valid_to == 0xffffffffffffffffULL) {
1098 		snprintf(ret, sizeof(ret), "after %s", from);
1099 		return ret;
1100 	}
1101 
1102 	snprintf(ret, sizeof(ret), "from %s to %s", from, to);
1103 	return ret;
1104 }
1105 
1106 static void
1107 add_flag_constraint(Buffer *c, const char *name)
1108 {
1109 	debug3("%s: %s", __func__, name);
1110 	buffer_put_cstring(c, name);
1111 	buffer_put_string(c, NULL, 0);
1112 }
1113 
1114 static void
1115 add_string_constraint(Buffer *c, const char *name, const char *value)
1116 {
1117 	Buffer b;
1118 
1119 	debug3("%s: %s=%s", __func__, name, value);
1120 	buffer_init(&b);
1121 	buffer_put_cstring(&b, value);
1122 
1123 	buffer_put_cstring(c, name);
1124 	buffer_put_string(c, buffer_ptr(&b), buffer_len(&b));
1125 
1126 	buffer_free(&b);
1127 }
1128 
1129 static void
1130 prepare_constraint_buf(Buffer *c)
1131 {
1132 
1133 	buffer_clear(c);
1134 	if ((constraint_flags & CONSTRAINT_X_FWD) != 0)
1135 		add_flag_constraint(c, "permit-X11-forwarding");
1136 	if ((constraint_flags & CONSTRAINT_AGENT_FWD) != 0)
1137 		add_flag_constraint(c, "permit-agent-forwarding");
1138 	if ((constraint_flags & CONSTRAINT_PORT_FWD) != 0)
1139 		add_flag_constraint(c, "permit-port-forwarding");
1140 	if ((constraint_flags & CONSTRAINT_PTY) != 0)
1141 		add_flag_constraint(c, "permit-pty");
1142 	if ((constraint_flags & CONSTRAINT_USER_RC) != 0)
1143 		add_flag_constraint(c, "permit-user-rc");
1144 	if (constraint_command != NULL)
1145 		add_string_constraint(c, "force-command", constraint_command);
1146 	if (constraint_src_addr != NULL)
1147 		add_string_constraint(c, "source-address", constraint_src_addr);
1148 }
1149 
1150 static void
1151 do_ca_sign(struct passwd *pw, int argc, char **argv)
1152 {
1153 	int i, fd;
1154 	u_int n;
1155 	Key *ca, *public;
1156 	char *otmp, *tmp, *cp, *out, *comment, **plist = NULL;
1157 	FILE *f;
1158 
1159 	tmp = tilde_expand_filename(ca_key_path, pw->pw_uid);
1160 	if ((ca = load_identity(tmp)) == NULL)
1161 		fatal("Couldn't load CA key \"%s\"", tmp);
1162 	xfree(tmp);
1163 
1164 	for (i = 0; i < argc; i++) {
1165 		/* Split list of principals */
1166 		n = 0;
1167 		if (cert_principals != NULL) {
1168 			otmp = tmp = xstrdup(cert_principals);
1169 			plist = NULL;
1170 			for (; (cp = strsep(&tmp, ",")) != NULL; n++) {
1171 				plist = xrealloc(plist, n + 1, sizeof(*plist));
1172 				if (*(plist[n] = xstrdup(cp)) == '\0')
1173 					fatal("Empty principal name");
1174 			}
1175 			xfree(otmp);
1176 		}
1177 
1178 		tmp = tilde_expand_filename(argv[i], pw->pw_uid);
1179 		if ((public = key_load_public(tmp, &comment)) == NULL)
1180 			fatal("%s: unable to open \"%s\"", __func__, tmp);
1181 		if (public->type != KEY_RSA && public->type != KEY_DSA)
1182 			fatal("%s: key \"%s\" type %s cannot be certified",
1183 			    __func__, tmp, key_type(public));
1184 
1185 		/* Prepare certificate to sign */
1186 		if (key_to_certified(public) != 0)
1187 			fatal("Could not upgrade key %s to certificate", tmp);
1188 		public->cert->type = cert_key_type;
1189 		public->cert->key_id = xstrdup(cert_key_id);
1190 		public->cert->nprincipals = n;
1191 		public->cert->principals = plist;
1192 		public->cert->valid_after = cert_valid_from;
1193 		public->cert->valid_before = cert_valid_to;
1194 		prepare_constraint_buf(&public->cert->constraints);
1195 		public->cert->signature_key = key_from_private(ca);
1196 
1197 		if (key_certify(public, ca) != 0)
1198 			fatal("Couldn't not certify key %s", tmp);
1199 
1200 		if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0)
1201 			*cp = '\0';
1202 		xasprintf(&out, "%s-cert.pub", tmp);
1203 		xfree(tmp);
1204 
1205 		if ((fd = open(out, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1)
1206 			fatal("Could not open \"%s\" for writing: %s", out,
1207 			    strerror(errno));
1208 		if ((f = fdopen(fd, "w")) == NULL)
1209 			fatal("%s: fdopen: %s", __func__, strerror(errno));
1210 		if (!key_write(public, f))
1211 			fatal("Could not write certified key to %s", out);
1212 		fprintf(f, " %s\n", comment);
1213 		fclose(f);
1214 
1215 		if (!quiet)
1216 			logit("Signed %s key %s: id \"%s\"%s%s valid %s",
1217 			    cert_key_type == SSH2_CERT_TYPE_USER?"user":"host",
1218 			    out, cert_key_id,
1219 			    cert_principals != NULL ? " for " : "",
1220 			    cert_principals != NULL ? cert_principals : "",
1221 			    fmt_validity(cert_valid_from, cert_valid_to));
1222 
1223 		key_free(public);
1224 		xfree(out);
1225 	}
1226 	exit(0);
1227 }
1228 
1229 static u_int64_t
1230 parse_relative_time(const char *s, time_t now)
1231 {
1232 	int64_t mul, secs;
1233 
1234 	mul = *s == '-' ? -1 : 1;
1235 
1236 	if ((secs = convtime(s + 1)) == -1)
1237 		fatal("Invalid relative certificate time %s", s);
1238 	if (mul == -1 && secs > now)
1239 		fatal("Certificate time %s cannot be represented", s);
1240 	return now + (u_int64_t)(secs * mul);
1241 }
1242 
1243 static u_int64_t
1244 parse_absolute_time(const char *s)
1245 {
1246 	struct tm tm;
1247 	time_t tt;
1248 	char buf[32], *fmt;
1249 
1250 	/*
1251 	 * POSIX strptime says "The application shall ensure that there
1252 	 * is white-space or other non-alphanumeric characters between
1253 	 * any two conversion specifications" so arrange things this way.
1254 	 */
1255 	switch (strlen(s)) {
1256 	case 8:
1257 		fmt = "%Y-%m-%d";
1258 		snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2s", s, s + 4, s + 6);
1259 		break;
1260 	case 14:
1261 		fmt = "%Y-%m-%dT%H:%M:%S";
1262 		snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s:%.2s",
1263 		    s, s + 4, s + 6, s + 8, s + 10, s + 12);
1264 		break;
1265 	default:
1266 		fatal("Invalid certificate time format %s", s);
1267 	}
1268 
1269 	bzero(&tm, sizeof(tm));
1270 	if (strptime(buf, fmt, &tm) == NULL)
1271 		fatal("Invalid certificate time %s", s);
1272 	if ((tt = mktime(&tm)) < 0)
1273 		fatal("Certificate time %s cannot be represented", s);
1274 	return (u_int64_t)tt;
1275 }
1276 
1277 static void
1278 parse_cert_times(char *timespec)
1279 {
1280 	char *from, *to;
1281 	time_t now = time(NULL);
1282 	int64_t secs;
1283 
1284 	/* +timespec relative to now */
1285 	if (*timespec == '+' && strchr(timespec, ':') == NULL) {
1286 		if ((secs = convtime(timespec + 1)) == -1)
1287 			fatal("Invalid relative certificate life %s", timespec);
1288 		cert_valid_to = now + secs;
1289 		/*
1290 		 * Backdate certificate one minute to avoid problems on hosts
1291 		 * with poorly-synchronised clocks.
1292 		 */
1293 		cert_valid_from = ((now - 59)/ 60) * 60;
1294 		return;
1295 	}
1296 
1297 	/*
1298 	 * from:to, where
1299 	 * from := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS
1300 	 *   to := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS
1301 	 */
1302 	from = xstrdup(timespec);
1303 	to = strchr(from, ':');
1304 	if (to == NULL || from == to || *(to + 1) == '\0')
1305 		fatal("Invalid certificate life specification %s", timespec);
1306 	*to++ = '\0';
1307 
1308 	if (*from == '-' || *from == '+')
1309 		cert_valid_from = parse_relative_time(from, now);
1310 	else
1311 		cert_valid_from = parse_absolute_time(from);
1312 
1313 	if (*to == '-' || *to == '+')
1314 		cert_valid_to = parse_relative_time(to, cert_valid_from);
1315 	else
1316 		cert_valid_to = parse_absolute_time(to);
1317 
1318 	if (cert_valid_to <= cert_valid_from)
1319 		fatal("Empty certificate validity interval");
1320 	xfree(from);
1321 }
1322 
1323 static void
1324 add_cert_constraint(char *opt)
1325 {
1326 	char *val;
1327 
1328 	if (strcmp(opt, "clear") == 0)
1329 		constraint_flags = 0;
1330 	else if (strcasecmp(opt, "no-x11-forwarding") == 0)
1331 		constraint_flags &= ~CONSTRAINT_X_FWD;
1332 	else if (strcasecmp(opt, "permit-x11-forwarding") == 0)
1333 		constraint_flags |= CONSTRAINT_X_FWD;
1334 	else if (strcasecmp(opt, "no-agent-forwarding") == 0)
1335 		constraint_flags &= ~CONSTRAINT_AGENT_FWD;
1336 	else if (strcasecmp(opt, "permit-agent-forwarding") == 0)
1337 		constraint_flags |= CONSTRAINT_AGENT_FWD;
1338 	else if (strcasecmp(opt, "no-port-forwarding") == 0)
1339 		constraint_flags &= ~CONSTRAINT_PORT_FWD;
1340 	else if (strcasecmp(opt, "permit-port-forwarding") == 0)
1341 		constraint_flags |= CONSTRAINT_PORT_FWD;
1342 	else if (strcasecmp(opt, "no-pty") == 0)
1343 		constraint_flags &= ~CONSTRAINT_PTY;
1344 	else if (strcasecmp(opt, "permit-pty") == 0)
1345 		constraint_flags |= CONSTRAINT_PTY;
1346 	else if (strcasecmp(opt, "no-user-rc") == 0)
1347 		constraint_flags &= ~CONSTRAINT_USER_RC;
1348 	else if (strcasecmp(opt, "permit-user-rc") == 0)
1349 		constraint_flags |= CONSTRAINT_USER_RC;
1350 	else if (strncasecmp(opt, "force-command=", 14) == 0) {
1351 		val = opt + 14;
1352 		if (*val == '\0')
1353 			fatal("Empty force-command constraint");
1354 		if (constraint_command != NULL)
1355 			fatal("force-command already specified");
1356 		constraint_command = xstrdup(val);
1357 	} else if (strncasecmp(opt, "source-address=", 15) == 0) {
1358 		val = opt + 15;
1359 		if (*val == '\0')
1360 			fatal("Empty source-address constraint");
1361 		if (constraint_src_addr != NULL)
1362 			fatal("source-address already specified");
1363 		if (addr_match_cidr_list(NULL, val) != 0)
1364 			fatal("Invalid source-address list");
1365 		constraint_src_addr = xstrdup(val);
1366 	} else
1367 		fatal("Unsupported certificate constraint \"%s\"", opt);
1368 }
1369 
1370 static void
1371 do_show_cert(struct passwd *pw)
1372 {
1373 	Key *key;
1374 	struct stat st;
1375 	char *key_fp, *ca_fp;
1376 	Buffer constraints, constraint;
1377 	u_char *name, *data;
1378 	u_int i, dlen;
1379 
1380 	if (!have_identity)
1381 		ask_filename(pw, "Enter file in which the key is");
1382 	if (stat(identity_file, &st) < 0) {
1383 		perror(identity_file);
1384 		exit(1);
1385 	}
1386 	if ((key = key_load_public(identity_file, NULL)) == NULL)
1387 		fatal("%s is not a public key", identity_file);
1388 	if (!key_is_cert(key))
1389 		fatal("%s is not a certificate", identity_file);
1390 
1391 	key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
1392 	ca_fp = key_fingerprint(key->cert->signature_key,
1393 	    SSH_FP_MD5, SSH_FP_HEX);
1394 
1395 	printf("%s:\n", identity_file);
1396 	printf("        %s %s certificate %s\n", key_type(key),
1397 	    key_cert_type(key), key_fp);
1398 	printf("        Signed by %s CA %s\n",
1399 	    key_type(key->cert->signature_key), ca_fp);
1400 	printf("        Key ID \"%s\"\n", key->cert->key_id);
1401 	printf("        Valid: %s\n",
1402 	    fmt_validity(key->cert->valid_after, key->cert->valid_before));
1403 	printf("        Principals: ");
1404 	if (key->cert->nprincipals == 0)
1405 		printf("(none)\n");
1406 	else {
1407 		for (i = 0; i < key->cert->nprincipals; i++)
1408 			printf("\n                %s",
1409 			    key->cert->principals[i]);
1410 		printf("\n");
1411 	}
1412 	printf("        Constraints: ");
1413 	if (buffer_len(&key->cert->constraints) == 0)
1414 		printf("(none)\n");
1415 	else {
1416 		printf("\n");
1417 		buffer_init(&constraints);
1418 		buffer_append(&constraints,
1419 		    buffer_ptr(&key->cert->constraints),
1420 		    buffer_len(&key->cert->constraints));
1421 		buffer_init(&constraint);
1422 		while (buffer_len(&constraints) != 0) {
1423 			name = buffer_get_string(&constraints, NULL);
1424 			data = buffer_get_string_ptr(&constraints, &dlen);
1425 			buffer_append(&constraint, data, dlen);
1426 			printf("                %s", name);
1427 			if (strcmp(name, "permit-X11-forwarding") == 0 ||
1428 			    strcmp(name, "permit-agent-forwarding") == 0 ||
1429 			    strcmp(name, "permit-port-forwarding") == 0 ||
1430 			    strcmp(name, "permit-pty") == 0 ||
1431 			    strcmp(name, "permit-user-rc") == 0)
1432 				printf("\n");
1433 			else if (strcmp(name, "force-command") == 0 ||
1434 			    strcmp(name, "source-address") == 0) {
1435 				data = buffer_get_string(&constraint, NULL);
1436 				printf(" %s\n", data);
1437 				xfree(data);
1438 			} else {
1439 				printf(" UNKNOWN CONSTRAINT (len %u)\n",
1440 				    buffer_len(&constraint));
1441 				buffer_clear(&constraint);
1442 			}
1443 			xfree(name);
1444 			if (buffer_len(&constraint) != 0)
1445 				fatal("Constraint corrupt: extra data at end");
1446 		}
1447 		buffer_free(&constraint);
1448 		buffer_free(&constraints);
1449 	}
1450 
1451 	exit(0);
1452 }
1453 
1454 static void
1455 usage(void)
1456 {
1457 	fprintf(stderr, "usage: %s [options]\n", __progname);
1458 	fprintf(stderr, "Options:\n");
1459 	fprintf(stderr, "  -a trials   Number of trials for screening DH-GEX moduli.\n");
1460 	fprintf(stderr, "  -B          Show bubblebabble digest of key file.\n");
1461 	fprintf(stderr, "  -b bits     Number of bits in the key to create.\n");
1462 	fprintf(stderr, "  -C comment  Provide new comment.\n");
1463 	fprintf(stderr, "  -c          Change comment in private and public key files.\n");
1464 #ifdef ENABLE_PKCS11
1465 	fprintf(stderr, "  -D pkcs11   Download public key from pkcs11 token.\n");
1466 #endif
1467 	fprintf(stderr, "  -e          Convert OpenSSH to RFC 4716 key file.\n");
1468 	fprintf(stderr, "  -F hostname Find hostname in known hosts file.\n");
1469 	fprintf(stderr, "  -f filename Filename of the key file.\n");
1470 	fprintf(stderr, "  -G file     Generate candidates for DH-GEX moduli.\n");
1471 	fprintf(stderr, "  -g          Use generic DNS resource record format.\n");
1472 	fprintf(stderr, "  -H          Hash names in known_hosts file.\n");
1473 	fprintf(stderr, "  -h          Generate host certificate instead of a user certificate.\n");
1474 	fprintf(stderr, "  -I key_id   Key identifier to include in certificate.\n");
1475 	fprintf(stderr, "  -i          Convert RFC 4716 to OpenSSH key file.\n");
1476 	fprintf(stderr, "  -L          Print the contents of a certificate.\n");
1477 	fprintf(stderr, "  -l          Show fingerprint of key file.\n");
1478 	fprintf(stderr, "  -M memory   Amount of memory (MB) to use for generating DH-GEX moduli.\n");
1479 	fprintf(stderr, "  -n name,... User/host principal names to include in certificate\n");
1480 	fprintf(stderr, "  -N phrase   Provide new passphrase.\n");
1481 	fprintf(stderr, "  -O cnstr    Specify a certificate constraint.\n");
1482 	fprintf(stderr, "  -P phrase   Provide old passphrase.\n");
1483 	fprintf(stderr, "  -p          Change passphrase of private key file.\n");
1484 	fprintf(stderr, "  -q          Quiet.\n");
1485 	fprintf(stderr, "  -R hostname Remove host from known_hosts file.\n");
1486 	fprintf(stderr, "  -r hostname Print DNS resource record.\n");
1487 	fprintf(stderr, "  -s ca_key   Certify keys with CA key.\n");
1488 	fprintf(stderr, "  -S start    Start point (hex) for generating DH-GEX moduli.\n");
1489 	fprintf(stderr, "  -T file     Screen candidates for DH-GEX moduli.\n");
1490 	fprintf(stderr, "  -t type     Specify type of key to create.\n");
1491 	fprintf(stderr, "  -V from:to  Specify certificate validity interval.\n");
1492 	fprintf(stderr, "  -v          Verbose.\n");
1493 	fprintf(stderr, "  -W gen      Generator to use for generating DH-GEX moduli.\n");
1494 	fprintf(stderr, "  -y          Read private key file and print public key.\n");
1495 
1496 	exit(1);
1497 }
1498 
1499 /*
1500  * Main program for key management.
1501  */
1502 int
1503 main(int argc, char **argv)
1504 {
1505 	char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2;
1506 	char out_file[MAXPATHLEN], *pkcs11provider = NULL;
1507 	char *rr_hostname = NULL;
1508 	Key *private, *public;
1509 	struct passwd *pw;
1510 	struct stat st;
1511 	int opt, type, fd;
1512 	u_int32_t memory = 0, generator_wanted = 0, trials = 100;
1513 	int do_gen_candidates = 0, do_screen_candidates = 0;
1514 	BIGNUM *start = NULL;
1515 	FILE *f;
1516 	const char *errstr;
1517 
1518 	extern int optind;
1519 	extern char *optarg;
1520 
1521 	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1522 	sanitise_stdfd();
1523 
1524 	__progname = ssh_get_progname(argv[0]);
1525 
1526 	SSLeay_add_all_algorithms();
1527 	log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
1528 
1529 	init_rng();
1530 	seed_rng();
1531 
1532 	/* we need this for the home * directory.  */
1533 	pw = getpwuid(getuid());
1534 	if (!pw) {
1535 		printf("You don't exist, go away!\n");
1536 		exit(1);
1537 	}
1538 	if (gethostname(hostname, sizeof(hostname)) < 0) {
1539 		perror("gethostname");
1540 		exit(1);
1541 	}
1542 
1543 	while ((opt = getopt(argc, argv, "degiqpclBHLhvxXyF:b:f:t:D:I:P:N:n:"
1544 	    "O:C:r:g:R:T:G:M:S:s:a:V:W:")) != -1) {
1545 		switch (opt) {
1546 		case 'b':
1547 			bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr);
1548 			if (errstr)
1549 				fatal("Bits has bad value %s (%s)",
1550 					optarg, errstr);
1551 			break;
1552 		case 'F':
1553 			find_host = 1;
1554 			rr_hostname = optarg;
1555 			break;
1556 		case 'H':
1557 			hash_hosts = 1;
1558 			break;
1559 		case 'I':
1560 			cert_key_id = optarg;
1561 			break;
1562 		case 'R':
1563 			delete_host = 1;
1564 			rr_hostname = optarg;
1565 			break;
1566 		case 'L':
1567 			show_cert = 1;
1568 			break;
1569 		case 'l':
1570 			print_fingerprint = 1;
1571 			break;
1572 		case 'B':
1573 			print_bubblebabble = 1;
1574 			break;
1575 		case 'n':
1576 			cert_principals = optarg;
1577 			break;
1578 		case 'p':
1579 			change_passphrase = 1;
1580 			break;
1581 		case 'c':
1582 			change_comment = 1;
1583 			break;
1584 		case 'f':
1585 			if (strlcpy(identity_file, optarg, sizeof(identity_file)) >=
1586 			    sizeof(identity_file))
1587 				fatal("Identity filename too long");
1588 			have_identity = 1;
1589 			break;
1590 		case 'g':
1591 			print_generic = 1;
1592 			break;
1593 		case 'P':
1594 			identity_passphrase = optarg;
1595 			break;
1596 		case 'N':
1597 			identity_new_passphrase = optarg;
1598 			break;
1599 		case 'O':
1600 			add_cert_constraint(optarg);
1601 			break;
1602 		case 'C':
1603 			identity_comment = optarg;
1604 			break;
1605 		case 'q':
1606 			quiet = 1;
1607 			break;
1608 		case 'e':
1609 		case 'x':
1610 			/* export key */
1611 			convert_to_ssh2 = 1;
1612 			break;
1613 		case 'h':
1614 			cert_key_type = SSH2_CERT_TYPE_HOST;
1615 			constraint_flags = 0;
1616 			break;
1617 		case 'i':
1618 		case 'X':
1619 			/* import key */
1620 			convert_from_ssh2 = 1;
1621 			break;
1622 		case 'y':
1623 			print_public = 1;
1624 			break;
1625 		case 'd':
1626 			key_type_name = "dsa";
1627 			break;
1628 		case 's':
1629 			ca_key_path = optarg;
1630 			break;
1631 		case 't':
1632 			key_type_name = optarg;
1633 			break;
1634 		case 'D':
1635 			pkcs11provider = optarg;
1636 			break;
1637 		case 'v':
1638 			if (log_level == SYSLOG_LEVEL_INFO)
1639 				log_level = SYSLOG_LEVEL_DEBUG1;
1640 			else {
1641 				if (log_level >= SYSLOG_LEVEL_DEBUG1 &&
1642 				    log_level < SYSLOG_LEVEL_DEBUG3)
1643 					log_level++;
1644 			}
1645 			break;
1646 		case 'r':
1647 			rr_hostname = optarg;
1648 			break;
1649 		case 'W':
1650 			generator_wanted = (u_int32_t)strtonum(optarg, 1,
1651 			    UINT_MAX, &errstr);
1652 			if (errstr)
1653 				fatal("Desired generator has bad value: %s (%s)",
1654 					optarg, errstr);
1655 			break;
1656 		case 'a':
1657 			trials = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr);
1658 			if (errstr)
1659 				fatal("Invalid number of trials: %s (%s)",
1660 					optarg, errstr);
1661 			break;
1662 		case 'M':
1663 			memory = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr);
1664 			if (errstr) {
1665 				fatal("Memory limit is %s: %s", errstr, optarg);
1666 			}
1667 			break;
1668 		case 'G':
1669 			do_gen_candidates = 1;
1670 			if (strlcpy(out_file, optarg, sizeof(out_file)) >=
1671 			    sizeof(out_file))
1672 				fatal("Output filename too long");
1673 			break;
1674 		case 'T':
1675 			do_screen_candidates = 1;
1676 			if (strlcpy(out_file, optarg, sizeof(out_file)) >=
1677 			    sizeof(out_file))
1678 				fatal("Output filename too long");
1679 			break;
1680 		case 'S':
1681 			/* XXX - also compare length against bits */
1682 			if (BN_hex2bn(&start, optarg) == 0)
1683 				fatal("Invalid start point.");
1684 			break;
1685 		case 'V':
1686 			parse_cert_times(optarg);
1687 			break;
1688 		case '?':
1689 		default:
1690 			usage();
1691 		}
1692 	}
1693 
1694 	/* reinit */
1695 	log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1);
1696 
1697 	argv += optind;
1698 	argc -= optind;
1699 
1700 	if (ca_key_path != NULL) {
1701 		if (argc < 1) {
1702 			printf("Too few arguments.\n");
1703 			usage();
1704 		}
1705 	} else if (argc > 0) {
1706 		printf("Too many arguments.\n");
1707 		usage();
1708 	}
1709 	if (change_passphrase && change_comment) {
1710 		printf("Can only have one of -p and -c.\n");
1711 		usage();
1712 	}
1713 	if (print_fingerprint && (delete_host || hash_hosts)) {
1714 		printf("Cannot use -l with -D or -R.\n");
1715 		usage();
1716 	}
1717 	if (ca_key_path != NULL) {
1718 		if (cert_key_id == NULL)
1719 			fatal("Must specify key id (-I) when certifying");
1720 		do_ca_sign(pw, argc, argv);
1721 	}
1722 	if (show_cert)
1723 		do_show_cert(pw);
1724 	if (delete_host || hash_hosts || find_host)
1725 		do_known_hosts(pw, rr_hostname);
1726 	if (print_fingerprint || print_bubblebabble)
1727 		do_fingerprint(pw);
1728 	if (change_passphrase)
1729 		do_change_passphrase(pw);
1730 	if (change_comment)
1731 		do_change_comment(pw);
1732 	if (convert_to_ssh2)
1733 		do_convert_to_ssh2(pw);
1734 	if (convert_from_ssh2)
1735 		do_convert_from_ssh2(pw);
1736 	if (print_public)
1737 		do_print_public(pw);
1738 	if (rr_hostname != NULL) {
1739 		unsigned int n = 0;
1740 
1741 		if (have_identity) {
1742 			n = do_print_resource_record(pw,
1743 			    identity_file, rr_hostname);
1744 			if (n == 0) {
1745 				perror(identity_file);
1746 				exit(1);
1747 			}
1748 			exit(0);
1749 		} else {
1750 
1751 			n += do_print_resource_record(pw,
1752 			    _PATH_HOST_RSA_KEY_FILE, rr_hostname);
1753 			n += do_print_resource_record(pw,
1754 			    _PATH_HOST_DSA_KEY_FILE, rr_hostname);
1755 
1756 			if (n == 0)
1757 				fatal("no keys found.");
1758 			exit(0);
1759 		}
1760 	}
1761 	if (pkcs11provider != NULL)
1762 		do_download(pw, pkcs11provider);
1763 
1764 	if (do_gen_candidates) {
1765 		FILE *out = fopen(out_file, "w");
1766 
1767 		if (out == NULL) {
1768 			error("Couldn't open modulus candidate file \"%s\": %s",
1769 			    out_file, strerror(errno));
1770 			return (1);
1771 		}
1772 		if (bits == 0)
1773 			bits = DEFAULT_BITS;
1774 		if (gen_candidates(out, memory, bits, start) != 0)
1775 			fatal("modulus candidate generation failed");
1776 
1777 		return (0);
1778 	}
1779 
1780 	if (do_screen_candidates) {
1781 		FILE *in;
1782 		FILE *out = fopen(out_file, "w");
1783 
1784 		if (have_identity && strcmp(identity_file, "-") != 0) {
1785 			if ((in = fopen(identity_file, "r")) == NULL) {
1786 				fatal("Couldn't open modulus candidate "
1787 				    "file \"%s\": %s", identity_file,
1788 				    strerror(errno));
1789 			}
1790 		} else
1791 			in = stdin;
1792 
1793 		if (out == NULL) {
1794 			fatal("Couldn't open moduli file \"%s\": %s",
1795 			    out_file, strerror(errno));
1796 		}
1797 		if (prime_test(in, out, trials, generator_wanted) != 0)
1798 			fatal("modulus screening failed");
1799 		return (0);
1800 	}
1801 
1802 	arc4random_stir();
1803 
1804 	if (key_type_name == NULL)
1805 		key_type_name = "rsa";
1806 
1807 	type = key_type_from_name(key_type_name);
1808 	if (type == KEY_UNSPEC) {
1809 		fprintf(stderr, "unknown key type %s\n", key_type_name);
1810 		exit(1);
1811 	}
1812 	if (bits == 0)
1813 		bits = (type == KEY_DSA) ? DEFAULT_BITS_DSA : DEFAULT_BITS;
1814 	if (type == KEY_DSA && bits != 1024)
1815 		fatal("DSA keys must be 1024 bits");
1816 	if (!quiet)
1817 		printf("Generating public/private %s key pair.\n", key_type_name);
1818 	private = key_generate(type, bits);
1819 	if (private == NULL) {
1820 		fprintf(stderr, "key_generate failed\n");
1821 		exit(1);
1822 	}
1823 	public  = key_from_private(private);
1824 
1825 	if (!have_identity)
1826 		ask_filename(pw, "Enter file in which to save the key");
1827 
1828 	/* Create ~/.ssh directory if it doesn't already exist. */
1829 	snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR);
1830 	if (strstr(identity_file, dotsshdir) != NULL &&
1831 	    stat(dotsshdir, &st) < 0) {
1832 		if (mkdir(dotsshdir, 0700) < 0)
1833 			error("Could not create directory '%s'.", dotsshdir);
1834 		else if (!quiet)
1835 			printf("Created directory '%s'.\n", dotsshdir);
1836 	}
1837 	/* If the file already exists, ask the user to confirm. */
1838 	if (stat(identity_file, &st) >= 0) {
1839 		char yesno[3];
1840 		printf("%s already exists.\n", identity_file);
1841 		printf("Overwrite (y/n)? ");
1842 		fflush(stdout);
1843 		if (fgets(yesno, sizeof(yesno), stdin) == NULL)
1844 			exit(1);
1845 		if (yesno[0] != 'y' && yesno[0] != 'Y')
1846 			exit(1);
1847 	}
1848 	/* Ask for a passphrase (twice). */
1849 	if (identity_passphrase)
1850 		passphrase1 = xstrdup(identity_passphrase);
1851 	else if (identity_new_passphrase)
1852 		passphrase1 = xstrdup(identity_new_passphrase);
1853 	else {
1854 passphrase_again:
1855 		passphrase1 =
1856 			read_passphrase("Enter passphrase (empty for no "
1857 			    "passphrase): ", RP_ALLOW_STDIN);
1858 		passphrase2 = read_passphrase("Enter same passphrase again: ",
1859 		    RP_ALLOW_STDIN);
1860 		if (strcmp(passphrase1, passphrase2) != 0) {
1861 			/*
1862 			 * The passphrases do not match.  Clear them and
1863 			 * retry.
1864 			 */
1865 			memset(passphrase1, 0, strlen(passphrase1));
1866 			memset(passphrase2, 0, strlen(passphrase2));
1867 			xfree(passphrase1);
1868 			xfree(passphrase2);
1869 			printf("Passphrases do not match.  Try again.\n");
1870 			goto passphrase_again;
1871 		}
1872 		/* Clear the other copy of the passphrase. */
1873 		memset(passphrase2, 0, strlen(passphrase2));
1874 		xfree(passphrase2);
1875 	}
1876 
1877 	if (identity_comment) {
1878 		strlcpy(comment, identity_comment, sizeof(comment));
1879 	} else {
1880 		/* Create default comment field for the passphrase. */
1881 		snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
1882 	}
1883 
1884 	/* Save the key with the given passphrase and comment. */
1885 	if (!key_save_private(private, identity_file, passphrase1, comment)) {
1886 		printf("Saving the key failed: %s.\n", identity_file);
1887 		memset(passphrase1, 0, strlen(passphrase1));
1888 		xfree(passphrase1);
1889 		exit(1);
1890 	}
1891 	/* Clear the passphrase. */
1892 	memset(passphrase1, 0, strlen(passphrase1));
1893 	xfree(passphrase1);
1894 
1895 	/* Clear the private key and the random number generator. */
1896 	key_free(private);
1897 	arc4random_stir();
1898 
1899 	if (!quiet)
1900 		printf("Your identification has been saved in %s.\n", identity_file);
1901 
1902 	strlcat(identity_file, ".pub", sizeof(identity_file));
1903 	fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1904 	if (fd == -1) {
1905 		printf("Could not save your public key in %s\n", identity_file);
1906 		exit(1);
1907 	}
1908 	f = fdopen(fd, "w");
1909 	if (f == NULL) {
1910 		printf("fdopen %s failed\n", identity_file);
1911 		exit(1);
1912 	}
1913 	if (!key_write(public, f))
1914 		fprintf(stderr, "write key failed\n");
1915 	fprintf(f, " %s\n", comment);
1916 	fclose(f);
1917 
1918 	if (!quiet) {
1919 		char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
1920 		char *ra = key_fingerprint(public, SSH_FP_MD5,
1921 		    SSH_FP_RANDOMART);
1922 		printf("Your public key has been saved in %s.\n",
1923 		    identity_file);
1924 		printf("The key fingerprint is:\n");
1925 		printf("%s %s\n", fp, comment);
1926 		printf("The key's randomart image is:\n");
1927 		printf("%s\n", ra);
1928 		xfree(ra);
1929 		xfree(fp);
1930 	}
1931 
1932 	key_free(public);
1933 	exit(0);
1934 }
1935