blob: 83450fe840bf90e0d8ca0989c5c7026477dcf398 [file] [log] [blame]
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001/*
Damien Miller95def091999-11-25 00:26:21 +11002 * 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 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10008
9#include "includes.h"
Damien Millerad833b32000-08-23 10:46:23 +100010RCSID("$OpenBSD: ssh-keygen.c,v 1.30 2000/08/19 21:34:43 markus Exp $");
Damien Millerd4a8b7e1999-10-27 13:42:43 +100011
Damien Millereba71ba2000-04-29 23:57:08 +100012#include <openssl/evp.h>
13#include <openssl/pem.h>
14#include <openssl/rsa.h>
15#include <openssl/dsa.h>
16
Damien Millerd4a8b7e1999-10-27 13:42:43 +100017#include "ssh.h"
18#include "xmalloc.h"
Damien Millereba71ba2000-04-29 23:57:08 +100019#include "key.h"
20#include "rsa.h"
21#include "dsa.h"
22#include "authfile.h"
23#include "uuencode.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100024
Damien Millereba71ba2000-04-29 23:57:08 +100025/* Number of bits in the RSA/DSA key. This value can be changed on the command line. */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100026int bits = 1024;
27
Damien Miller5428f641999-11-25 11:54:57 +110028/*
29 * Flag indicating that we just want to change the passphrase. This can be
30 * set on the command line.
31 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100032int change_passphrase = 0;
33
Damien Miller5428f641999-11-25 11:54:57 +110034/*
35 * Flag indicating that we just want to change the comment. This can be set
36 * on the command line.
37 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100038int change_comment = 0;
39
40int quiet = 0;
41
Damien Miller10f6f6b1999-11-17 17:29:08 +110042/* Flag indicating that we just want to see the key fingerprint */
43int print_fingerprint = 0;
44
Damien Miller431f66b1999-11-21 18:31:57 +110045/* The identity file name, given on the command line or entered by the user. */
46char identity_file[1024];
47int have_identity = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100048
49/* This is set to the passphrase if given on the command line. */
50char *identity_passphrase = NULL;
51
52/* This is set to the new passphrase if given on the command line. */
53char *identity_new_passphrase = NULL;
54
55/* This is set to the new comment if given on the command line. */
56char *identity_comment = NULL;
57
Damien Millereba71ba2000-04-29 23:57:08 +100058/* Dump public key file in format used by real and the original SSH 2 */
59int convert_to_ssh2 = 0;
60int convert_from_ssh2 = 0;
61int print_public = 0;
62int dsa_mode = 0;
63
Damien Miller431f66b1999-11-21 18:31:57 +110064/* argv0 */
Damien Miller95def091999-11-25 00:26:21 +110065#ifdef HAVE___PROGNAME
Damien Miller431f66b1999-11-21 18:31:57 +110066extern char *__progname;
Damien Miller95def091999-11-25 00:26:21 +110067#else /* HAVE___PROGNAME */
Damien Miller70fb6712000-05-01 20:59:50 +100068static const char *__progname = "ssh-keygen";
Damien Miller95def091999-11-25 00:26:21 +110069#endif /* HAVE___PROGNAME */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100070
Damien Millereba71ba2000-04-29 23:57:08 +100071char hostname[MAXHOSTNAMELEN];
72
Damien Miller431f66b1999-11-21 18:31:57 +110073void
74ask_filename(struct passwd *pw, const char *prompt)
Damien Millerd4a8b7e1999-10-27 13:42:43 +100075{
Damien Miller95def091999-11-25 00:26:21 +110076 char buf[1024];
77 snprintf(identity_file, sizeof(identity_file), "%s/%s",
Damien Millere247cc42000-05-07 12:03:14 +100078 pw->pw_dir,
79 dsa_mode ? SSH_CLIENT_ID_DSA: SSH_CLIENT_IDENTITY);
Damien Miller95def091999-11-25 00:26:21 +110080 printf("%s (%s): ", prompt, identity_file);
81 fflush(stdout);
82 if (fgets(buf, sizeof(buf), stdin) == NULL)
83 exit(1);
84 if (strchr(buf, '\n'))
85 *strchr(buf, '\n') = 0;
86 if (strcmp(buf, "") != 0)
87 strlcpy(identity_file, buf, sizeof(identity_file));
88 have_identity = 1;
Damien Miller10f6f6b1999-11-17 17:29:08 +110089}
Damien Millerd4a8b7e1999-10-27 13:42:43 +100090
Damien Millereba71ba2000-04-29 23:57:08 +100091int
92try_load_key(char *filename, Key *k)
93{
94 int success = 1;
95 if (!load_private_key(filename, "", k, NULL)) {
96 char *pass = read_passphrase("Enter passphrase: ", 1);
97 if (!load_private_key(filename, pass, k, NULL)) {
98 success = 0;
99 }
100 memset(pass, 0, strlen(pass));
101 xfree(pass);
102 }
103 return success;
104}
105
106#define SSH_COM_MAGIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
107#define SSH_COM_MAGIC_END "---- END SSH2 PUBLIC KEY ----"
108
109void
110do_convert_to_ssh2(struct passwd *pw)
111{
112 Key *k;
113 int len;
114 unsigned char *blob;
115 struct stat st;
116
117 if (!have_identity)
118 ask_filename(pw, "Enter file in which the key is");
119 if (stat(identity_file, &st) < 0) {
120 perror(identity_file);
121 exit(1);
122 }
123 k = key_new(KEY_DSA);
124 if (!try_load_key(identity_file, k)) {
125 fprintf(stderr, "load failed\n");
126 exit(1);
127 }
128 dsa_make_key_blob(k, &blob, &len);
Damien Miller37023962000-07-11 17:31:38 +1000129 fprintf(stdout, "%s\n", SSH_COM_MAGIC_BEGIN);
Damien Millereba71ba2000-04-29 23:57:08 +1000130 fprintf(stdout,
131 "Comment: \"%d-bit DSA, converted from openssh by %s@%s\"\n",
132 BN_num_bits(k->dsa->p),
133 pw->pw_name, hostname);
134 dump_base64(stdout, blob, len);
Damien Miller37023962000-07-11 17:31:38 +1000135 fprintf(stdout, "%s\n", SSH_COM_MAGIC_END);
Damien Millereba71ba2000-04-29 23:57:08 +1000136 key_free(k);
137 xfree(blob);
138 exit(0);
139}
140
141void
142do_convert_from_ssh2(struct passwd *pw)
143{
144 Key *k;
145 int blen;
146 char line[1024], *p;
147 char blob[8096];
148 char encoded[8096];
149 struct stat st;
Damien Miller30c3d422000-05-09 11:02:59 +1000150 int escaped = 0;
Damien Millereba71ba2000-04-29 23:57:08 +1000151 FILE *fp;
152
153 if (!have_identity)
154 ask_filename(pw, "Enter file in which the key is");
155 if (stat(identity_file, &st) < 0) {
156 perror(identity_file);
157 exit(1);
158 }
159 fp = fopen(identity_file, "r");
160 if (fp == NULL) {
161 perror(identity_file);
162 exit(1);
163 }
164 encoded[0] = '\0';
165 while (fgets(line, sizeof(line), fp)) {
Damien Miller30c3d422000-05-09 11:02:59 +1000166 if (!(p = strchr(line, '\n'))) {
167 fprintf(stderr, "input line too long.\n");
168 exit(1);
169 }
170 if (p > line && p[-1] == '\\')
171 escaped++;
Damien Millereba71ba2000-04-29 23:57:08 +1000172 if (strncmp(line, "----", 4) == 0 ||
173 strstr(line, ": ") != NULL) {
174 fprintf(stderr, "ignore: %s", line);
175 continue;
176 }
Damien Miller30c3d422000-05-09 11:02:59 +1000177 if (escaped) {
178 escaped--;
179 fprintf(stderr, "escaped: %s", line);
180 continue;
Damien Millereba71ba2000-04-29 23:57:08 +1000181 }
182 *p = '\0';
183 strlcat(encoded, line, sizeof(encoded));
184 }
185 blen = uudecode(encoded, (unsigned char *)blob, sizeof(blob));
186 if (blen < 0) {
187 fprintf(stderr, "uudecode failed.\n");
188 exit(1);
189 }
190 k = dsa_key_from_blob(blob, blen);
191 if (!key_write(k, stdout))
192 fprintf(stderr, "key_write failed");
193 key_free(k);
194 fprintf(stdout, "\n");
195 fclose(fp);
196 exit(0);
197}
198
199void
200do_print_public(struct passwd *pw)
201{
202 Key *k;
203 int len;
204 unsigned char *blob;
205 struct stat st;
206
207 if (!have_identity)
208 ask_filename(pw, "Enter file in which the key is");
209 if (stat(identity_file, &st) < 0) {
210 perror(identity_file);
211 exit(1);
212 }
213 k = key_new(KEY_DSA);
214 if (!try_load_key(identity_file, k)) {
215 fprintf(stderr, "load failed\n");
216 exit(1);
217 }
218 dsa_make_key_blob(k, &blob, &len);
219 if (!key_write(k, stdout))
220 fprintf(stderr, "key_write failed");
221 key_free(k);
222 xfree(blob);
223 fprintf(stdout, "\n");
224 exit(0);
225}
226
Damien Miller10f6f6b1999-11-17 17:29:08 +1100227void
228do_fingerprint(struct passwd *pw)
229{
Damien Millerad833b32000-08-23 10:46:23 +1000230 /* XXX RSA1 only */
231
Damien Miller98c7ad62000-03-09 21:27:49 +1100232 FILE *f;
Damien Millereba71ba2000-04-29 23:57:08 +1000233 Key *public;
Damien Miller98c7ad62000-03-09 21:27:49 +1100234 char *comment = NULL, *cp, *ep, line[16*1024];
235 int i, skip = 0, num = 1, invalid = 1;
Damien Miller7684ee12000-03-17 23:40:15 +1100236 unsigned int ignore;
Damien Miller95def091999-11-25 00:26:21 +1100237 struct stat st;
Damien Miller10f6f6b1999-11-17 17:29:08 +1100238
Damien Miller95def091999-11-25 00:26:21 +1100239 if (!have_identity)
240 ask_filename(pw, "Enter file in which the key is");
241 if (stat(identity_file, &st) < 0) {
242 perror(identity_file);
243 exit(1);
244 }
Damien Millereba71ba2000-04-29 23:57:08 +1000245 public = key_new(KEY_RSA);
246 if (load_public_key(identity_file, public, &comment)) {
247 printf("%d %s %s\n", BN_num_bits(public->rsa->n),
248 key_fingerprint(public), comment);
249 key_free(public);
Damien Miller98c7ad62000-03-09 21:27:49 +1100250 exit(0);
251 }
Damien Miller98c7ad62000-03-09 21:27:49 +1100252
253 f = fopen(identity_file, "r");
254 if (f != NULL) {
Damien Miller98c7ad62000-03-09 21:27:49 +1100255 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;
Damien Miller95def091999-11-25 00:26:21 +1100261 }
Damien Miller98c7ad62000-03-09 21:27:49 +1100262 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;
Damien Millerad833b32000-08-23 10:46:23 +1000289 if (auth_rsa_read_key(&cp, &ignore, public->rsa->e, public->rsa->n)) {
Damien Miller98c7ad62000-03-09 21:27:49 +1100290 invalid = 0;
291 comment = *cp ? cp : comment;
Damien Millerad833b32000-08-23 10:46:23 +1000292 printf("%d %s %s\n", key_size(public),
293 key_fingerprint(public),
Damien Miller98c7ad62000-03-09 21:27:49 +1100294 comment ? comment : "no comment");
295 }
Damien Miller95def091999-11-25 00:26:21 +1100296 }
Damien Miller98c7ad62000-03-09 21:27:49 +1100297 fclose(f);
Damien Miller95def091999-11-25 00:26:21 +1100298 }
Damien Millerad833b32000-08-23 10:46:23 +1000299 key_free(public);
Damien Miller98c7ad62000-03-09 21:27:49 +1100300 if (invalid) {
301 printf("%s is not a valid key file.\n", identity_file);
302 exit(1);
303 }
Damien Miller95def091999-11-25 00:26:21 +1100304 exit(0);
Damien Miller10f6f6b1999-11-17 17:29:08 +1100305}
306
Damien Miller95def091999-11-25 00:26:21 +1100307/*
308 * Perform changing a passphrase. The argument is the passwd structure
309 * for the current user.
310 */
Damien Miller10f6f6b1999-11-17 17:29:08 +1100311void
312do_change_passphrase(struct passwd *pw)
313{
Damien Miller95def091999-11-25 00:26:21 +1100314 char *comment;
315 char *old_passphrase, *passphrase1, *passphrase2;
316 struct stat st;
Damien Millereba71ba2000-04-29 23:57:08 +1000317 Key *private;
318 Key *public;
319 int type = dsa_mode ? KEY_DSA : KEY_RSA;
Damien Miller10f6f6b1999-11-17 17:29:08 +1100320
Damien Miller95def091999-11-25 00:26:21 +1100321 if (!have_identity)
322 ask_filename(pw, "Enter file in which the key is");
Damien Miller95def091999-11-25 00:26:21 +1100323 if (stat(identity_file, &st) < 0) {
324 perror(identity_file);
325 exit(1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000326 }
Damien Millereba71ba2000-04-29 23:57:08 +1000327
328 if (type == KEY_RSA) {
329 /* XXX this works currently only for RSA */
330 public = key_new(type);
331 if (!load_public_key(identity_file, public, NULL)) {
332 printf("%s is not a valid key file.\n", identity_file);
333 exit(1);
334 }
335 /* Clear the public key since we are just about to load the whole file. */
336 key_free(public);
Damien Miller95def091999-11-25 00:26:21 +1100337 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000338
Damien Miller95def091999-11-25 00:26:21 +1100339 /* Try to load the file with empty passphrase. */
Damien Millereba71ba2000-04-29 23:57:08 +1000340 private = key_new(type);
341 if (!load_private_key(identity_file, "", private, &comment)) {
Damien Miller95def091999-11-25 00:26:21 +1100342 if (identity_passphrase)
343 old_passphrase = xstrdup(identity_passphrase);
344 else
345 old_passphrase = read_passphrase("Enter old passphrase: ", 1);
Damien Millereba71ba2000-04-29 23:57:08 +1000346 if (!load_private_key(identity_file, old_passphrase, private, &comment)) {
Damien Miller95def091999-11-25 00:26:21 +1100347 memset(old_passphrase, 0, strlen(old_passphrase));
348 xfree(old_passphrase);
349 printf("Bad passphrase.\n");
350 exit(1);
351 }
Damien Miller95def091999-11-25 00:26:21 +1100352 memset(old_passphrase, 0, strlen(old_passphrase));
353 xfree(old_passphrase);
354 }
355 printf("Key has comment '%s'\n", comment);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000356
Damien Miller95def091999-11-25 00:26:21 +1100357 /* Ask the new passphrase (twice). */
358 if (identity_new_passphrase) {
359 passphrase1 = xstrdup(identity_new_passphrase);
360 passphrase2 = NULL;
361 } else {
362 passphrase1 =
363 read_passphrase("Enter new passphrase (empty for no passphrase): ", 1);
364 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
365
366 /* Verify that they are the same. */
367 if (strcmp(passphrase1, passphrase2) != 0) {
368 memset(passphrase1, 0, strlen(passphrase1));
369 memset(passphrase2, 0, strlen(passphrase2));
370 xfree(passphrase1);
371 xfree(passphrase2);
372 printf("Pass phrases do not match. Try again.\n");
373 exit(1);
374 }
375 /* Destroy the other copy. */
376 memset(passphrase2, 0, strlen(passphrase2));
377 xfree(passphrase2);
378 }
379
380 /* Save the file using the new passphrase. */
Damien Millereba71ba2000-04-29 23:57:08 +1000381 if (!save_private_key(identity_file, passphrase1, private, comment)) {
Damien Miller95def091999-11-25 00:26:21 +1100382 printf("Saving the key failed: %s: %s.\n",
383 identity_file, strerror(errno));
384 memset(passphrase1, 0, strlen(passphrase1));
385 xfree(passphrase1);
Damien Millereba71ba2000-04-29 23:57:08 +1000386 key_free(private);
Damien Miller95def091999-11-25 00:26:21 +1100387 xfree(comment);
388 exit(1);
389 }
390 /* Destroy the passphrase and the copy of the key in memory. */
391 memset(passphrase1, 0, strlen(passphrase1));
392 xfree(passphrase1);
Damien Millereba71ba2000-04-29 23:57:08 +1000393 key_free(private); /* Destroys contents */
Damien Miller95def091999-11-25 00:26:21 +1100394 xfree(comment);
395
396 printf("Your identification has been saved with the new passphrase.\n");
397 exit(0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000398}
399
Damien Miller95def091999-11-25 00:26:21 +1100400/*
401 * Change the comment of a private key file.
402 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000403void
404do_change_comment(struct passwd *pw)
405{
Damien Miller95def091999-11-25 00:26:21 +1100406 char new_comment[1024], *comment;
Damien Millereba71ba2000-04-29 23:57:08 +1000407 Key *private;
408 Key *public;
Damien Miller95def091999-11-25 00:26:21 +1100409 char *passphrase;
410 struct stat st;
411 FILE *f;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000412
Damien Miller95def091999-11-25 00:26:21 +1100413 if (!have_identity)
414 ask_filename(pw, "Enter file in which the key is");
Damien Miller95def091999-11-25 00:26:21 +1100415 if (stat(identity_file, &st) < 0) {
416 perror(identity_file);
417 exit(1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000418 }
Damien Miller5428f641999-11-25 11:54:57 +1100419 /*
420 * Try to load the public key from the file the verify that it is
421 * readable and of the proper format.
422 */
Damien Millereba71ba2000-04-29 23:57:08 +1000423 public = key_new(KEY_RSA);
424 if (!load_public_key(identity_file, public, NULL)) {
Damien Miller95def091999-11-25 00:26:21 +1100425 printf("%s is not a valid key file.\n", identity_file);
426 exit(1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000427 }
Damien Miller5428f641999-11-25 11:54:57 +1100428
Damien Millereba71ba2000-04-29 23:57:08 +1000429 private = key_new(KEY_RSA);
430 if (load_private_key(identity_file, "", private, &comment))
Damien Miller95def091999-11-25 00:26:21 +1100431 passphrase = xstrdup("");
432 else {
Damien Miller95def091999-11-25 00:26:21 +1100433 if (identity_passphrase)
434 passphrase = xstrdup(identity_passphrase);
435 else if (identity_new_passphrase)
436 passphrase = xstrdup(identity_new_passphrase);
437 else
438 passphrase = read_passphrase("Enter passphrase: ", 1);
439 /* Try to load using the passphrase. */
Damien Millereba71ba2000-04-29 23:57:08 +1000440 if (!load_private_key(identity_file, passphrase, private, &comment)) {
Damien Miller95def091999-11-25 00:26:21 +1100441 memset(passphrase, 0, strlen(passphrase));
442 xfree(passphrase);
443 printf("Bad passphrase.\n");
444 exit(1);
445 }
446 }
447 printf("Key now has comment '%s'\n", comment);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000448
Damien Miller95def091999-11-25 00:26:21 +1100449 if (identity_comment) {
450 strlcpy(new_comment, identity_comment, sizeof(new_comment));
451 } else {
452 printf("Enter new comment: ");
453 fflush(stdout);
454 if (!fgets(new_comment, sizeof(new_comment), stdin)) {
455 memset(passphrase, 0, strlen(passphrase));
Damien Millereba71ba2000-04-29 23:57:08 +1000456 key_free(private);
Damien Miller95def091999-11-25 00:26:21 +1100457 exit(1);
458 }
Damien Miller95def091999-11-25 00:26:21 +1100459 if (strchr(new_comment, '\n'))
460 *strchr(new_comment, '\n') = 0;
461 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000462
Damien Miller95def091999-11-25 00:26:21 +1100463 /* Save the file using the new passphrase. */
Damien Millereba71ba2000-04-29 23:57:08 +1000464 if (!save_private_key(identity_file, passphrase, private, new_comment)) {
Damien Miller95def091999-11-25 00:26:21 +1100465 printf("Saving the key failed: %s: %s.\n",
466 identity_file, strerror(errno));
467 memset(passphrase, 0, strlen(passphrase));
468 xfree(passphrase);
Damien Millereba71ba2000-04-29 23:57:08 +1000469 key_free(private);
Damien Miller95def091999-11-25 00:26:21 +1100470 xfree(comment);
471 exit(1);
472 }
Damien Miller95def091999-11-25 00:26:21 +1100473 memset(passphrase, 0, strlen(passphrase));
474 xfree(passphrase);
Damien Millereba71ba2000-04-29 23:57:08 +1000475 key_free(private);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000476
Damien Miller95def091999-11-25 00:26:21 +1100477 strlcat(identity_file, ".pub", sizeof(identity_file));
478 f = fopen(identity_file, "w");
479 if (!f) {
480 printf("Could not save your public key in %s\n", identity_file);
481 exit(1);
482 }
Damien Millereba71ba2000-04-29 23:57:08 +1000483 if (!key_write(public, f))
484 fprintf(stderr, "write key failed");
485 key_free(public);
486 fprintf(f, " %s\n", new_comment);
Damien Miller95def091999-11-25 00:26:21 +1100487 fclose(f);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000488
Damien Miller95def091999-11-25 00:26:21 +1100489 xfree(comment);
490
491 printf("The comment in your key file has been changed.\n");
492 exit(0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000493}
494
Damien Miller431f66b1999-11-21 18:31:57 +1100495void
496usage(void)
497{
Damien Millere247cc42000-05-07 12:03:14 +1000498 printf("Usage: %s [-lpqxXydc] [-b bits] [-f file] [-C comment] [-N new-pass] [-P pass]\n", __progname);
Damien Miller95def091999-11-25 00:26:21 +1100499 exit(1);
Damien Miller431f66b1999-11-21 18:31:57 +1100500}
501
Damien Miller95def091999-11-25 00:26:21 +1100502/*
503 * Main program for key management.
504 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000505int
506main(int ac, char **av)
507{
Damien Miller95def091999-11-25 00:26:21 +1100508 char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
509 struct passwd *pw;
Damien Miller95def091999-11-25 00:26:21 +1100510 int opt;
511 struct stat st;
512 FILE *f;
Damien Millereba71ba2000-04-29 23:57:08 +1000513 Key *private;
514 Key *public;
Damien Miller95def091999-11-25 00:26:21 +1100515 extern int optind;
516 extern char *optarg;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000517
Damien Millerf9b625c2000-07-09 22:42:32 +1000518 init_rng();
519
Damien Millerd3a18572000-06-07 19:55:44 +1000520 SSLeay_add_all_algorithms();
Damien Millereba71ba2000-04-29 23:57:08 +1000521
Damien Miller5428f641999-11-25 11:54:57 +1100522 /* we need this for the home * directory. */
Damien Miller95def091999-11-25 00:26:21 +1100523 pw = getpwuid(getuid());
524 if (!pw) {
525 printf("You don't exist, go away!\n");
526 exit(1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000527 }
Damien Millereba71ba2000-04-29 23:57:08 +1000528 if (gethostname(hostname, sizeof(hostname)) < 0) {
529 perror("gethostname");
530 exit(1);
531 }
Damien Miller5428f641999-11-25 11:54:57 +1100532
Damien Millereba71ba2000-04-29 23:57:08 +1000533 while ((opt = getopt(ac, av, "dqpclRxXyb:f:P:N:C:")) != EOF) {
Damien Miller95def091999-11-25 00:26:21 +1100534 switch (opt) {
535 case 'b':
536 bits = atoi(optarg);
537 if (bits < 512 || bits > 32768) {
538 printf("Bits has bad value.\n");
539 exit(1);
540 }
541 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000542
Damien Miller95def091999-11-25 00:26:21 +1100543 case 'l':
544 print_fingerprint = 1;
545 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000546
Damien Miller95def091999-11-25 00:26:21 +1100547 case 'p':
548 change_passphrase = 1;
549 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000550
Damien Miller95def091999-11-25 00:26:21 +1100551 case 'c':
552 change_comment = 1;
553 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000554
Damien Miller95def091999-11-25 00:26:21 +1100555 case 'f':
556 strlcpy(identity_file, optarg, sizeof(identity_file));
557 have_identity = 1;
558 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000559
Damien Miller95def091999-11-25 00:26:21 +1100560 case 'P':
561 identity_passphrase = optarg;
562 break;
563
564 case 'N':
565 identity_new_passphrase = optarg;
566 break;
567
568 case 'C':
569 identity_comment = optarg;
570 break;
571
572 case 'q':
573 quiet = 1;
574 break;
575
Damien Millereba71ba2000-04-29 23:57:08 +1000576 case 'R':
577 if (rsa_alive() == 0)
578 exit(1);
579 else
580 exit(0);
581 break;
582
583 case 'x':
584 convert_to_ssh2 = 1;
585 break;
586
587 case 'X':
588 convert_from_ssh2 = 1;
589 break;
590
591 case 'y':
592 print_public = 1;
593 break;
594
595 case 'd':
596 dsa_mode = 1;
597 break;
598
Damien Miller95def091999-11-25 00:26:21 +1100599 case '?':
600 default:
601 usage();
602 }
603 }
604 if (optind < ac) {
605 printf("Too many arguments.\n");
606 usage();
607 }
608 if (change_passphrase && change_comment) {
609 printf("Can only have one of -p and -c.\n");
610 usage();
611 }
Damien Millereba71ba2000-04-29 23:57:08 +1000612 /* check if RSA support is needed and exists */
613 if (dsa_mode == 0 && rsa_alive() == 0) {
614 fprintf(stderr,
615 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
616 __progname);
617 exit(1);
618 }
Damien Miller95def091999-11-25 00:26:21 +1100619 if (print_fingerprint)
620 do_fingerprint(pw);
Damien Miller95def091999-11-25 00:26:21 +1100621 if (change_passphrase)
622 do_change_passphrase(pw);
Damien Miller95def091999-11-25 00:26:21 +1100623 if (change_comment)
624 do_change_comment(pw);
Damien Millereba71ba2000-04-29 23:57:08 +1000625 if (convert_to_ssh2)
626 do_convert_to_ssh2(pw);
627 if (convert_from_ssh2)
628 do_convert_from_ssh2(pw);
629 if (print_public)
630 do_print_public(pw);
Damien Miller95def091999-11-25 00:26:21 +1100631
632 arc4random_stir();
633
Damien Millereba71ba2000-04-29 23:57:08 +1000634 if (dsa_mode != 0) {
635 if (!quiet)
636 printf("Generating DSA parameter and key.\n");
637 public = private = dsa_generate_key(bits);
638 if (private == NULL) {
639 fprintf(stderr, "dsa_generate_keys failed");
640 exit(1);
641 }
642 } else {
643 if (quiet)
644 rsa_set_verbose(0);
645 /* Generate the rsa key pair. */
646 public = key_new(KEY_RSA);
647 private = key_new(KEY_RSA);
648 rsa_generate_key(private->rsa, public->rsa, bits);
649 }
Damien Miller95def091999-11-25 00:26:21 +1100650
651 if (!have_identity)
652 ask_filename(pw, "Enter file in which to save the key");
653
654 /* Create ~/.ssh directory if it doesn\'t already exist. */
655 snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, SSH_USER_DIR);
656 if (strstr(identity_file, dotsshdir) != NULL &&
657 stat(dotsshdir, &st) < 0) {
Damien Millerbe484b52000-07-15 14:14:16 +1000658 if (mkdir(dotsshdir, 0700) < 0)
Damien Miller95def091999-11-25 00:26:21 +1100659 error("Could not create directory '%s'.", dotsshdir);
660 else if (!quiet)
661 printf("Created directory '%s'.\n", dotsshdir);
662 }
663 /* If the file already exists, ask the user to confirm. */
664 if (stat(identity_file, &st) >= 0) {
665 char yesno[3];
666 printf("%s already exists.\n", identity_file);
667 printf("Overwrite (y/n)? ");
668 fflush(stdout);
669 if (fgets(yesno, sizeof(yesno), stdin) == NULL)
670 exit(1);
671 if (yesno[0] != 'y' && yesno[0] != 'Y')
672 exit(1);
673 }
674 /* Ask for a passphrase (twice). */
675 if (identity_passphrase)
676 passphrase1 = xstrdup(identity_passphrase);
677 else if (identity_new_passphrase)
678 passphrase1 = xstrdup(identity_new_passphrase);
679 else {
680passphrase_again:
681 passphrase1 =
682 read_passphrase("Enter passphrase (empty for no passphrase): ", 1);
683 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
684 if (strcmp(passphrase1, passphrase2) != 0) {
685 /* The passphrases do not match. Clear them and retry. */
686 memset(passphrase1, 0, strlen(passphrase1));
687 memset(passphrase2, 0, strlen(passphrase2));
688 xfree(passphrase1);
689 xfree(passphrase2);
690 printf("Passphrases do not match. Try again.\n");
691 goto passphrase_again;
692 }
693 /* Clear the other copy of the passphrase. */
694 memset(passphrase2, 0, strlen(passphrase2));
695 xfree(passphrase2);
696 }
697
Damien Miller95def091999-11-25 00:26:21 +1100698 if (identity_comment) {
699 strlcpy(comment, identity_comment, sizeof(comment));
700 } else {
Damien Miller4af51302000-04-16 11:18:38 +1000701 /* Create default commend field for the passphrase. */
Damien Miller95def091999-11-25 00:26:21 +1100702 snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
703 }
704
705 /* Save the key with the given passphrase and comment. */
Damien Millereba71ba2000-04-29 23:57:08 +1000706 if (!save_private_key(identity_file, passphrase1, private, comment)) {
Damien Miller95def091999-11-25 00:26:21 +1100707 printf("Saving the key failed: %s: %s.\n",
Damien Millereba71ba2000-04-29 23:57:08 +1000708 identity_file, strerror(errno));
Damien Miller95def091999-11-25 00:26:21 +1100709 memset(passphrase1, 0, strlen(passphrase1));
710 xfree(passphrase1);
711 exit(1);
712 }
713 /* Clear the passphrase. */
714 memset(passphrase1, 0, strlen(passphrase1));
715 xfree(passphrase1);
716
717 /* Clear the private key and the random number generator. */
Damien Millereba71ba2000-04-29 23:57:08 +1000718 if (private != public) {
719 key_free(private);
720 }
Damien Miller95def091999-11-25 00:26:21 +1100721 arc4random_stir();
722
723 if (!quiet)
724 printf("Your identification has been saved in %s.\n", identity_file);
725
Damien Miller95def091999-11-25 00:26:21 +1100726 strlcat(identity_file, ".pub", sizeof(identity_file));
727 f = fopen(identity_file, "w");
728 if (!f) {
729 printf("Could not save your public key in %s\n", identity_file);
730 exit(1);
731 }
Damien Millereba71ba2000-04-29 23:57:08 +1000732 if (!key_write(public, f))
733 fprintf(stderr, "write key failed");
734 fprintf(f, " %s\n", comment);
Damien Miller95def091999-11-25 00:26:21 +1100735 fclose(f);
736
737 if (!quiet) {
Damien Millereba71ba2000-04-29 23:57:08 +1000738 printf("Your public key has been saved in %s.\n",
739 identity_file);
Damien Miller95def091999-11-25 00:26:21 +1100740 printf("The key fingerprint is:\n");
Damien Millereba71ba2000-04-29 23:57:08 +1000741 printf("%s %s\n", key_fingerprint(public), comment);
Damien Miller95def091999-11-25 00:26:21 +1100742 }
Damien Millereba71ba2000-04-29 23:57:08 +1000743
744 key_free(public);
Damien Miller95def091999-11-25 00:26:21 +1100745 exit(0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000746}