ssh-keygen.c revision 60573
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 * Created: Mon Mar 27 02:26:40 1995 ylo
6 * Identity and host key generation and maintenance.
7 */
8
9#include "includes.h"
10RCSID("$Id: ssh-keygen.c,v 1.25 2000/05/08 18:23:07 markus Exp $");
11
12#include <openssl/evp.h>
13#include <openssl/pem.h>
14#include <openssl/rsa.h>
15#include <openssl/dsa.h>
16
17#include "ssh.h"
18#include "xmalloc.h"
19#include "fingerprint.h"
20#include "key.h"
21#include "rsa.h"
22#include "dsa.h"
23#include "authfile.h"
24#include "uuencode.h"
25
26/* Number of bits in the RSA/DSA key.  This value can be changed on the command line. */
27int bits = 1024;
28
29/*
30 * Flag indicating that we just want to change the passphrase.  This can be
31 * set on the command line.
32 */
33int change_passphrase = 0;
34
35/*
36 * Flag indicating that we just want to change the comment.  This can be set
37 * on the command line.
38 */
39int change_comment = 0;
40
41int quiet = 0;
42
43/* Flag indicating that we just want to see the key fingerprint */
44int print_fingerprint = 0;
45
46/* The identity file name, given on the command line or entered by the user. */
47char identity_file[1024];
48int have_identity = 0;
49
50/* This is set to the passphrase if given on the command line. */
51char *identity_passphrase = NULL;
52
53/* This is set to the new passphrase if given on the command line. */
54char *identity_new_passphrase = NULL;
55
56/* This is set to the new comment if given on the command line. */
57char *identity_comment = NULL;
58
59/* Dump public key file in format used by real and the original SSH 2 */
60int convert_to_ssh2 = 0;
61int convert_from_ssh2 = 0;
62int print_public = 0;
63int dsa_mode = 0;
64
65/* argv0 */
66extern char *__progname;
67
68char hostname[MAXHOSTNAMELEN];
69
70void
71ask_filename(struct passwd *pw, const char *prompt)
72{
73	char buf[1024];
74	snprintf(identity_file, sizeof(identity_file), "%s/%s",
75	    pw->pw_dir,
76	    dsa_mode ? SSH_CLIENT_ID_DSA: SSH_CLIENT_IDENTITY);
77	printf("%s (%s): ", prompt, identity_file);
78	fflush(stdout);
79	if (fgets(buf, sizeof(buf), stdin) == NULL)
80		exit(1);
81	if (strchr(buf, '\n'))
82		*strchr(buf, '\n') = 0;
83	if (strcmp(buf, "") != 0)
84		strlcpy(identity_file, buf, sizeof(identity_file));
85	have_identity = 1;
86}
87
88int
89try_load_key(char *filename, Key *k)
90{
91	int success = 1;
92	if (!load_private_key(filename, "", k, NULL)) {
93		char *pass = read_passphrase("Enter passphrase: ", 1);
94		if (!load_private_key(filename, pass, k, NULL)) {
95			success = 0;
96		}
97		memset(pass, 0, strlen(pass));
98		xfree(pass);
99	}
100	return success;
101}
102
103#define SSH_COM_MAGIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
104#define SSH_COM_MAGIC_END   "---- END SSH2 PUBLIC KEY ----"
105
106void
107do_convert_to_ssh2(struct passwd *pw)
108{
109	Key *k;
110	int len;
111	unsigned char *blob;
112	struct stat st;
113
114	if (!have_identity)
115		ask_filename(pw, "Enter file in which the key is");
116	if (stat(identity_file, &st) < 0) {
117		perror(identity_file);
118		exit(1);
119	}
120	k = key_new(KEY_DSA);
121	if (!try_load_key(identity_file, k)) {
122		fprintf(stderr, "load failed\n");
123		exit(1);
124	}
125	dsa_make_key_blob(k, &blob, &len);
126	fprintf(stdout, SSH_COM_MAGIC_BEGIN "\n");
127	fprintf(stdout,
128	    "Comment: \"%d-bit DSA, converted from openssh by %s@%s\"\n",
129	    BN_num_bits(k->dsa->p),
130	    pw->pw_name, hostname);
131	dump_base64(stdout, blob, len);
132	fprintf(stdout, SSH_COM_MAGIC_END "\n");
133	key_free(k);
134	xfree(blob);
135	exit(0);
136}
137
138void
139do_convert_from_ssh2(struct passwd *pw)
140{
141	Key *k;
142	int blen;
143	char line[1024], *p;
144	char blob[8096];
145	char encoded[8096];
146	struct stat st;
147	int escaped = 0;
148	FILE *fp;
149
150	if (!have_identity)
151		ask_filename(pw, "Enter file in which the key is");
152	if (stat(identity_file, &st) < 0) {
153		perror(identity_file);
154		exit(1);
155	}
156	fp = fopen(identity_file, "r");
157	if (fp == NULL) {
158		perror(identity_file);
159		exit(1);
160	}
161	encoded[0] = '\0';
162	while (fgets(line, sizeof(line), fp)) {
163		if (!(p = strchr(line, '\n'))) {
164			fprintf(stderr, "input line too long.\n");
165			exit(1);
166		}
167		if (p > line && p[-1] == '\\')
168			escaped++;
169		if (strncmp(line, "----", 4) == 0 ||
170		    strstr(line, ": ") != NULL) {
171			fprintf(stderr, "ignore: %s", line);
172			continue;
173		}
174		if (escaped) {
175			escaped--;
176			fprintf(stderr, "escaped: %s", line);
177			continue;
178		}
179		*p = '\0';
180		strlcat(encoded, line, sizeof(encoded));
181	}
182	blen = uudecode(encoded, (unsigned char *)blob, sizeof(blob));
183	if (blen < 0) {
184		fprintf(stderr, "uudecode failed.\n");
185		exit(1);
186	}
187	k = dsa_key_from_blob(blob, blen);
188	if (!key_write(k, stdout))
189		fprintf(stderr, "key_write failed");
190	key_free(k);
191	fprintf(stdout, "\n");
192	fclose(fp);
193	exit(0);
194}
195
196void
197do_print_public(struct passwd *pw)
198{
199	Key *k;
200	int len;
201	unsigned char *blob;
202	struct stat st;
203
204	if (!have_identity)
205		ask_filename(pw, "Enter file in which the key is");
206	if (stat(identity_file, &st) < 0) {
207		perror(identity_file);
208		exit(1);
209	}
210	k = key_new(KEY_DSA);
211	if (!try_load_key(identity_file, k)) {
212		fprintf(stderr, "load failed\n");
213		exit(1);
214	}
215	dsa_make_key_blob(k, &blob, &len);
216	if (!key_write(k, stdout))
217		fprintf(stderr, "key_write failed");
218	key_free(k);
219	xfree(blob);
220	fprintf(stdout, "\n");
221	exit(0);
222}
223
224void
225do_fingerprint(struct passwd *pw)
226{
227	FILE *f;
228	BIGNUM *e, *n;
229	Key *public;
230	char *comment = NULL, *cp, *ep, line[16*1024];
231	int i, skip = 0, num = 1, invalid = 1;
232	unsigned int ignore;
233	struct stat st;
234
235	if (!have_identity)
236		ask_filename(pw, "Enter file in which the key is");
237	if (stat(identity_file, &st) < 0) {
238		perror(identity_file);
239		exit(1);
240	}
241	public = key_new(KEY_RSA);
242	if (load_public_key(identity_file, public, &comment)) {
243		printf("%d %s %s\n", BN_num_bits(public->rsa->n),
244		    key_fingerprint(public), comment);
245		key_free(public);
246		exit(0);
247	}
248	key_free(public);
249
250	/* XXX */
251	f = fopen(identity_file, "r");
252	if (f != NULL) {
253		n = BN_new();
254		e = BN_new();
255		while (fgets(line, sizeof(line), f)) {
256			i = strlen(line) - 1;
257			if (line[i] != '\n') {
258				error("line %d too long: %.40s...", num, line);
259				skip = 1;
260				continue;
261			}
262			num++;
263			if (skip) {
264				skip = 0;
265				continue;
266			}
267			line[i] = '\0';
268
269			/* Skip leading whitespace, empty and comment lines. */
270			for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
271				;
272			if (!*cp || *cp == '\n' || *cp == '#')
273				continue ;
274			i = strtol(cp, &ep, 10);
275			if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
276				int quoted = 0;
277				comment = cp;
278				for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
279					if (*cp == '\\' && cp[1] == '"')
280						cp++;	/* Skip both */
281					else if (*cp == '"')
282						quoted = !quoted;
283				}
284				if (!*cp)
285					continue;
286				*cp++ = '\0';
287			}
288			ep = cp;
289			if (auth_rsa_read_key(&cp, &ignore, e, n)) {
290				invalid = 0;
291				comment = *cp ? cp : comment;
292				printf("%d %s %s\n", BN_num_bits(n),
293				    fingerprint(e, n),
294				    comment ? comment : "no comment");
295			}
296		}
297		BN_free(e);
298		BN_free(n);
299		fclose(f);
300	}
301	if (invalid) {
302		printf("%s is not a valid key file.\n", identity_file);
303		exit(1);
304	}
305	exit(0);
306}
307
308/*
309 * Perform changing a passphrase.  The argument is the passwd structure
310 * for the current user.
311 */
312void
313do_change_passphrase(struct passwd *pw)
314{
315	char *comment;
316	char *old_passphrase, *passphrase1, *passphrase2;
317	struct stat st;
318	Key *private;
319	Key *public;
320	int type = dsa_mode ? KEY_DSA : KEY_RSA;
321
322	if (!have_identity)
323		ask_filename(pw, "Enter file in which the key is");
324	if (stat(identity_file, &st) < 0) {
325		perror(identity_file);
326		exit(1);
327	}
328
329	if (type == KEY_RSA) {
330		/* XXX this works currently only for RSA */
331		public = key_new(type);
332		if (!load_public_key(identity_file, public, NULL)) {
333			printf("%s is not a valid key file.\n", identity_file);
334			exit(1);
335		}
336		/* Clear the public key since we are just about to load the whole file. */
337		key_free(public);
338	}
339
340	/* Try to load the file with empty passphrase. */
341	private = key_new(type);
342	if (!load_private_key(identity_file, "", private, &comment)) {
343		if (identity_passphrase)
344			old_passphrase = xstrdup(identity_passphrase);
345		else
346			old_passphrase = read_passphrase("Enter old passphrase: ", 1);
347		if (!load_private_key(identity_file, old_passphrase, private, &comment)) {
348			memset(old_passphrase, 0, strlen(old_passphrase));
349			xfree(old_passphrase);
350			printf("Bad passphrase.\n");
351			exit(1);
352		}
353		memset(old_passphrase, 0, strlen(old_passphrase));
354		xfree(old_passphrase);
355	}
356	printf("Key has comment '%s'\n", comment);
357
358	/* Ask the new passphrase (twice). */
359	if (identity_new_passphrase) {
360		passphrase1 = xstrdup(identity_new_passphrase);
361		passphrase2 = NULL;
362	} else {
363		passphrase1 =
364			read_passphrase("Enter new passphrase (empty for no passphrase): ", 1);
365		passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
366
367		/* Verify that they are the same. */
368		if (strcmp(passphrase1, passphrase2) != 0) {
369			memset(passphrase1, 0, strlen(passphrase1));
370			memset(passphrase2, 0, strlen(passphrase2));
371			xfree(passphrase1);
372			xfree(passphrase2);
373			printf("Pass phrases do not match.  Try again.\n");
374			exit(1);
375		}
376		/* Destroy the other copy. */
377		memset(passphrase2, 0, strlen(passphrase2));
378		xfree(passphrase2);
379	}
380
381	/* Save the file using the new passphrase. */
382	if (!save_private_key(identity_file, passphrase1, private, comment)) {
383		printf("Saving the key failed: %s: %s.\n",
384		       identity_file, strerror(errno));
385		memset(passphrase1, 0, strlen(passphrase1));
386		xfree(passphrase1);
387		key_free(private);
388		xfree(comment);
389		exit(1);
390	}
391	/* Destroy the passphrase and the copy of the key in memory. */
392	memset(passphrase1, 0, strlen(passphrase1));
393	xfree(passphrase1);
394	key_free(private);		 /* Destroys contents */
395	xfree(comment);
396
397	printf("Your identification has been saved with the new passphrase.\n");
398	exit(0);
399}
400
401/*
402 * Change the comment of a private key file.
403 */
404void
405do_change_comment(struct passwd *pw)
406{
407	char new_comment[1024], *comment;
408	Key *private;
409	Key *public;
410	char *passphrase;
411	struct stat st;
412	FILE *f;
413
414	if (!have_identity)
415		ask_filename(pw, "Enter file in which the key is");
416	if (stat(identity_file, &st) < 0) {
417		perror(identity_file);
418		exit(1);
419	}
420	/*
421	 * Try to load the public key from the file the verify that it is
422	 * readable and of the proper format.
423	 */
424	public = key_new(KEY_RSA);
425	if (!load_public_key(identity_file, public, NULL)) {
426		printf("%s is not a valid key file.\n", identity_file);
427		exit(1);
428	}
429
430	private = key_new(KEY_RSA);
431	if (load_private_key(identity_file, "", private, &comment))
432		passphrase = xstrdup("");
433	else {
434		if (identity_passphrase)
435			passphrase = xstrdup(identity_passphrase);
436		else if (identity_new_passphrase)
437			passphrase = xstrdup(identity_new_passphrase);
438		else
439			passphrase = read_passphrase("Enter passphrase: ", 1);
440		/* Try to load using the passphrase. */
441		if (!load_private_key(identity_file, passphrase, private, &comment)) {
442			memset(passphrase, 0, strlen(passphrase));
443			xfree(passphrase);
444			printf("Bad passphrase.\n");
445			exit(1);
446		}
447	}
448	printf("Key now has comment '%s'\n", comment);
449
450	if (identity_comment) {
451		strlcpy(new_comment, identity_comment, sizeof(new_comment));
452	} else {
453		printf("Enter new comment: ");
454		fflush(stdout);
455		if (!fgets(new_comment, sizeof(new_comment), stdin)) {
456			memset(passphrase, 0, strlen(passphrase));
457			key_free(private);
458			exit(1);
459		}
460		if (strchr(new_comment, '\n'))
461			*strchr(new_comment, '\n') = 0;
462	}
463
464	/* Save the file using the new passphrase. */
465	if (!save_private_key(identity_file, passphrase, private, new_comment)) {
466		printf("Saving the key failed: %s: %s.\n",
467		       identity_file, strerror(errno));
468		memset(passphrase, 0, strlen(passphrase));
469		xfree(passphrase);
470		key_free(private);
471		xfree(comment);
472		exit(1);
473	}
474	memset(passphrase, 0, strlen(passphrase));
475	xfree(passphrase);
476	key_free(private);
477
478	strlcat(identity_file, ".pub", sizeof(identity_file));
479	f = fopen(identity_file, "w");
480	if (!f) {
481		printf("Could not save your public key in %s\n", identity_file);
482		exit(1);
483	}
484	if (!key_write(public, f))
485		fprintf(stderr, "write key failed");
486	key_free(public);
487	fprintf(f, " %s\n", new_comment);
488	fclose(f);
489
490	xfree(comment);
491
492	printf("The comment in your key file has been changed.\n");
493	exit(0);
494}
495
496void
497usage(void)
498{
499	printf("Usage: %s [-lpqxXydc] [-b bits] [-f file] [-C comment] [-N new-pass] [-P pass]\n", __progname);
500	exit(1);
501}
502
503/*
504 * Main program for key management.
505 */
506int
507main(int ac, char **av)
508{
509	char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
510	struct passwd *pw;
511	int opt;
512	struct stat st;
513	FILE *f;
514	Key *private;
515	Key *public;
516	extern int optind;
517	extern char *optarg;
518
519	OpenSSL_add_all_algorithms();
520
521	/* we need this for the home * directory.  */
522	pw = getpwuid(getuid());
523	if (!pw) {
524		printf("You don't exist, go away!\n");
525		exit(1);
526	}
527	if (gethostname(hostname, sizeof(hostname)) < 0) {
528		perror("gethostname");
529		exit(1);
530	}
531
532	while ((opt = getopt(ac, av, "dqpclRxXyb:f:P:N:C:")) != EOF) {
533		switch (opt) {
534		case 'b':
535			bits = atoi(optarg);
536			if (bits < 512 || bits > 32768) {
537				printf("Bits has bad value.\n");
538				exit(1);
539			}
540			break;
541
542		case 'l':
543			print_fingerprint = 1;
544			break;
545
546		case 'p':
547			change_passphrase = 1;
548			break;
549
550		case 'c':
551			change_comment = 1;
552			break;
553
554		case 'f':
555			strlcpy(identity_file, optarg, sizeof(identity_file));
556			have_identity = 1;
557			break;
558
559		case 'P':
560			identity_passphrase = optarg;
561			break;
562
563		case 'N':
564			identity_new_passphrase = optarg;
565			break;
566
567		case 'C':
568			identity_comment = optarg;
569			break;
570
571		case 'q':
572			quiet = 1;
573			break;
574
575		case 'R':
576			if (rsa_alive() == 0)
577				exit(1);
578			else
579				exit(0);
580			break;
581
582		case 'x':
583			convert_to_ssh2 = 1;
584			break;
585
586		case 'X':
587			convert_from_ssh2 = 1;
588			break;
589
590		case 'y':
591			print_public = 1;
592			break;
593
594		case 'd':
595			dsa_mode = 1;
596			break;
597
598		case '?':
599		default:
600			usage();
601		}
602	}
603	if (optind < ac) {
604		printf("Too many arguments.\n");
605		usage();
606	}
607	if (change_passphrase && change_comment) {
608		printf("Can only have one of -p and -c.\n");
609		usage();
610	}
611	/* check if RSA support is needed and exists */
612	if (dsa_mode == 0 && rsa_alive() == 0) {
613		fprintf(stderr,
614			"%s: no RSA support in libssl and libcrypto.  See ssl(8).\n",
615			__progname);
616		exit(1);
617	}
618	if (print_fingerprint)
619		do_fingerprint(pw);
620	if (change_passphrase)
621		do_change_passphrase(pw);
622	if (change_comment)
623		do_change_comment(pw);
624	if (convert_to_ssh2)
625		do_convert_to_ssh2(pw);
626	if (convert_from_ssh2)
627		do_convert_from_ssh2(pw);
628	if (print_public)
629		do_print_public(pw);
630
631	arc4random_stir();
632
633	if (dsa_mode != 0) {
634		if (!quiet)
635			printf("Generating DSA parameter and key.\n");
636		public = private = dsa_generate_key(bits);
637		if (private == NULL) {
638			fprintf(stderr, "dsa_generate_keys failed");
639			exit(1);
640		}
641	} else {
642		if (quiet)
643			rsa_set_verbose(0);
644		/* Generate the rsa key pair. */
645		public = key_new(KEY_RSA);
646		private = key_new(KEY_RSA);
647		rsa_generate_key(private->rsa, public->rsa, bits);
648	}
649
650	if (!have_identity)
651		ask_filename(pw, "Enter file in which to save the key");
652
653	/* Create ~/.ssh directory if it doesn\'t already exist. */
654	snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, SSH_USER_DIR);
655	if (strstr(identity_file, dotsshdir) != NULL &&
656	    stat(dotsshdir, &st) < 0) {
657		if (mkdir(dotsshdir, 0755) < 0)
658			error("Could not create directory '%s'.", dotsshdir);
659		else if (!quiet)
660			printf("Created directory '%s'.\n", dotsshdir);
661	}
662	/* If the file already exists, ask the user to confirm. */
663	if (stat(identity_file, &st) >= 0) {
664		char yesno[3];
665		printf("%s already exists.\n", identity_file);
666		printf("Overwrite (y/n)? ");
667		fflush(stdout);
668		if (fgets(yesno, sizeof(yesno), stdin) == NULL)
669			exit(1);
670		if (yesno[0] != 'y' && yesno[0] != 'Y')
671			exit(1);
672	}
673	/* Ask for a passphrase (twice). */
674	if (identity_passphrase)
675		passphrase1 = xstrdup(identity_passphrase);
676	else if (identity_new_passphrase)
677		passphrase1 = xstrdup(identity_new_passphrase);
678	else {
679passphrase_again:
680		passphrase1 =
681			read_passphrase("Enter passphrase (empty for no passphrase): ", 1);
682		passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
683		if (strcmp(passphrase1, passphrase2) != 0) {
684			/* The passphrases do not match.  Clear them and retry. */
685			memset(passphrase1, 0, strlen(passphrase1));
686			memset(passphrase2, 0, strlen(passphrase2));
687			xfree(passphrase1);
688			xfree(passphrase2);
689			printf("Passphrases do not match.  Try again.\n");
690			goto passphrase_again;
691		}
692		/* Clear the other copy of the passphrase. */
693		memset(passphrase2, 0, strlen(passphrase2));
694		xfree(passphrase2);
695	}
696
697	if (identity_comment) {
698		strlcpy(comment, identity_comment, sizeof(comment));
699	} else {
700		/* Create default commend field for the passphrase. */
701		snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
702	}
703
704	/* Save the key with the given passphrase and comment. */
705	if (!save_private_key(identity_file, passphrase1, private, comment)) {
706		printf("Saving the key failed: %s: %s.\n",
707		    identity_file, strerror(errno));
708		memset(passphrase1, 0, strlen(passphrase1));
709		xfree(passphrase1);
710		exit(1);
711	}
712	/* Clear the passphrase. */
713	memset(passphrase1, 0, strlen(passphrase1));
714	xfree(passphrase1);
715
716	/* Clear the private key and the random number generator. */
717	if (private != public) {
718		key_free(private);
719	}
720	arc4random_stir();
721
722	if (!quiet)
723		printf("Your identification has been saved in %s.\n", identity_file);
724
725	strlcat(identity_file, ".pub", sizeof(identity_file));
726	f = fopen(identity_file, "w");
727	if (!f) {
728		printf("Could not save your public key in %s\n", identity_file);
729		exit(1);
730	}
731	if (!key_write(public, f))
732		fprintf(stderr, "write key failed");
733	fprintf(f, " %s\n", comment);
734	fclose(f);
735
736	if (!quiet) {
737		printf("Your public key has been saved in %s.\n",
738		    identity_file);
739		printf("The key fingerprint is:\n");
740		printf("%s %s\n", key_fingerprint(public), comment);
741	}
742
743	key_free(public);
744	exit(0);
745}
746