blob: 0155949fd061177b4fbe0ea62d19d9224134cd54 [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 Millereba71ba2000-04-29 23:57:08 +100010RCSID("$Id: ssh-keygen.c,v 1.14 2000/04/29 13:57:12 damien 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 Miller10f6f6b1999-11-17 17:29:08 +110019#include "fingerprint.h"
Damien Millereba71ba2000-04-29 23:57:08 +100020#include "key.h"
21#include "rsa.h"
22#include "dsa.h"
23#include "authfile.h"
24#include "uuencode.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100025
Damien Millereba71ba2000-04-29 23:57:08 +100026/* Number of bits in the RSA/DSA key. This value can be changed on the command line. */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100027int bits = 1024;
28
Damien Miller5428f641999-11-25 11:54:57 +110029/*
30 * Flag indicating that we just want to change the passphrase. This can be
31 * set on the command line.
32 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100033int change_passphrase = 0;
34
Damien Miller5428f641999-11-25 11:54:57 +110035/*
36 * Flag indicating that we just want to change the comment. This can be set
37 * on the command line.
38 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100039int change_comment = 0;
40
41int quiet = 0;
42
Damien Miller10f6f6b1999-11-17 17:29:08 +110043/* Flag indicating that we just want to see the key fingerprint */
44int print_fingerprint = 0;
45
Damien Miller431f66b1999-11-21 18:31:57 +110046/* The identity file name, given on the command line or entered by the user. */
47char identity_file[1024];
48int have_identity = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100049
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
Damien Millereba71ba2000-04-29 23:57:08 +100059/* 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
Damien Miller431f66b1999-11-21 18:31:57 +110065/* argv0 */
Damien Miller95def091999-11-25 00:26:21 +110066#ifdef HAVE___PROGNAME
Damien Miller431f66b1999-11-21 18:31:57 +110067extern char *__progname;
Damien Miller95def091999-11-25 00:26:21 +110068#else /* HAVE___PROGNAME */
69const char *__progname = "ssh-keygen";
70#endif /* HAVE___PROGNAME */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100071
Damien Millereba71ba2000-04-29 23:57:08 +100072char hostname[MAXHOSTNAMELEN];
73
Damien Miller431f66b1999-11-21 18:31:57 +110074void
75ask_filename(struct passwd *pw, const char *prompt)
Damien Millerd4a8b7e1999-10-27 13:42:43 +100076{
Damien Miller95def091999-11-25 00:26:21 +110077 char buf[1024];
78 snprintf(identity_file, sizeof(identity_file), "%s/%s",
79 pw->pw_dir, SSH_CLIENT_IDENTITY);
80 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);
129 fprintf(stdout, SSH_COM_MAGIC_BEGIN "\n");
130 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);
135 fprintf(stdout, SSH_COM_MAGIC_END "\n");
136 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;
150 FILE *fp;
151
152 if (!have_identity)
153 ask_filename(pw, "Enter file in which the key is");
154 if (stat(identity_file, &st) < 0) {
155 perror(identity_file);
156 exit(1);
157 }
158 fp = fopen(identity_file, "r");
159 if (fp == NULL) {
160 perror(identity_file);
161 exit(1);
162 }
163 encoded[0] = '\0';
164 while (fgets(line, sizeof(line), fp)) {
165 if (strncmp(line, "----", 4) == 0 ||
166 strstr(line, ": ") != NULL) {
167 fprintf(stderr, "ignore: %s", line);
168 continue;
169 }
170 if (!(p = strchr(line, '\n'))) {
171 fprintf(stderr, "input line too long.\n");
172 exit(1);
173 }
174 *p = '\0';
175 strlcat(encoded, line, sizeof(encoded));
176 }
177 blen = uudecode(encoded, (unsigned char *)blob, sizeof(blob));
178 if (blen < 0) {
179 fprintf(stderr, "uudecode failed.\n");
180 exit(1);
181 }
182 k = dsa_key_from_blob(blob, blen);
183 if (!key_write(k, stdout))
184 fprintf(stderr, "key_write failed");
185 key_free(k);
186 fprintf(stdout, "\n");
187 fclose(fp);
188 exit(0);
189}
190
191void
192do_print_public(struct passwd *pw)
193{
194 Key *k;
195 int len;
196 unsigned char *blob;
197 struct stat st;
198
199 if (!have_identity)
200 ask_filename(pw, "Enter file in which the key is");
201 if (stat(identity_file, &st) < 0) {
202 perror(identity_file);
203 exit(1);
204 }
205 k = key_new(KEY_DSA);
206 if (!try_load_key(identity_file, k)) {
207 fprintf(stderr, "load failed\n");
208 exit(1);
209 }
210 dsa_make_key_blob(k, &blob, &len);
211 if (!key_write(k, stdout))
212 fprintf(stderr, "key_write failed");
213 key_free(k);
214 xfree(blob);
215 fprintf(stdout, "\n");
216 exit(0);
217}
218
Damien Miller10f6f6b1999-11-17 17:29:08 +1100219void
220do_fingerprint(struct passwd *pw)
221{
Damien Miller98c7ad62000-03-09 21:27:49 +1100222 FILE *f;
223 BIGNUM *e, *n;
Damien Millereba71ba2000-04-29 23:57:08 +1000224 Key *public;
Damien Miller98c7ad62000-03-09 21:27:49 +1100225 char *comment = NULL, *cp, *ep, line[16*1024];
226 int i, skip = 0, num = 1, invalid = 1;
Damien Miller7684ee12000-03-17 23:40:15 +1100227 unsigned int ignore;
Damien Miller95def091999-11-25 00:26:21 +1100228 struct stat st;
Damien Miller10f6f6b1999-11-17 17:29:08 +1100229
Damien Miller95def091999-11-25 00:26:21 +1100230 if (!have_identity)
231 ask_filename(pw, "Enter file in which the key is");
232 if (stat(identity_file, &st) < 0) {
233 perror(identity_file);
234 exit(1);
235 }
Damien Millereba71ba2000-04-29 23:57:08 +1000236 public = key_new(KEY_RSA);
237 if (load_public_key(identity_file, public, &comment)) {
238 printf("%d %s %s\n", BN_num_bits(public->rsa->n),
239 key_fingerprint(public), comment);
240 key_free(public);
Damien Miller98c7ad62000-03-09 21:27:49 +1100241 exit(0);
242 }
Damien Millereba71ba2000-04-29 23:57:08 +1000243 key_free(public);
Damien Miller98c7ad62000-03-09 21:27:49 +1100244
Damien Millereba71ba2000-04-29 23:57:08 +1000245 /* XXX */
Damien Miller98c7ad62000-03-09 21:27:49 +1100246 f = fopen(identity_file, "r");
247 if (f != NULL) {
Damien Miller95def091999-11-25 00:26:21 +1100248 n = BN_new();
249 e = BN_new();
Damien Miller98c7ad62000-03-09 21:27:49 +1100250 while (fgets(line, sizeof(line), f)) {
251 i = strlen(line) - 1;
252 if (line[i] != '\n') {
253 error("line %d too long: %.40s...", num, line);
254 skip = 1;
255 continue;
Damien Miller95def091999-11-25 00:26:21 +1100256 }
Damien Miller98c7ad62000-03-09 21:27:49 +1100257 num++;
258 if (skip) {
259 skip = 0;
260 continue;
261 }
262 line[i] = '\0';
263
264 /* Skip leading whitespace, empty and comment lines. */
265 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
266 ;
267 if (!*cp || *cp == '\n' || *cp == '#')
268 continue ;
269 i = strtol(cp, &ep, 10);
270 if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
271 int quoted = 0;
272 comment = cp;
273 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
274 if (*cp == '\\' && cp[1] == '"')
275 cp++; /* Skip both */
276 else if (*cp == '"')
277 quoted = !quoted;
278 }
279 if (!*cp)
280 continue;
281 *cp++ = '\0';
282 }
283 ep = cp;
Damien Miller7684ee12000-03-17 23:40:15 +1100284 if (auth_rsa_read_key(&cp, &ignore, e, n)) {
Damien Miller98c7ad62000-03-09 21:27:49 +1100285 invalid = 0;
286 comment = *cp ? cp : comment;
287 printf("%d %s %s\n", BN_num_bits(n),
288 fingerprint(e, n),
289 comment ? comment : "no comment");
290 }
Damien Miller95def091999-11-25 00:26:21 +1100291 }
Damien Miller98c7ad62000-03-09 21:27:49 +1100292 BN_free(e);
293 BN_free(n);
294 fclose(f);
Damien Miller95def091999-11-25 00:26:21 +1100295 }
Damien Miller98c7ad62000-03-09 21:27:49 +1100296 if (invalid) {
297 printf("%s is not a valid key file.\n", identity_file);
298 exit(1);
299 }
Damien Miller95def091999-11-25 00:26:21 +1100300 exit(0);
Damien Miller10f6f6b1999-11-17 17:29:08 +1100301}
302
Damien Miller95def091999-11-25 00:26:21 +1100303/*
304 * Perform changing a passphrase. The argument is the passwd structure
305 * for the current user.
306 */
Damien Miller10f6f6b1999-11-17 17:29:08 +1100307void
308do_change_passphrase(struct passwd *pw)
309{
Damien Miller95def091999-11-25 00:26:21 +1100310 char *comment;
311 char *old_passphrase, *passphrase1, *passphrase2;
312 struct stat st;
Damien Millereba71ba2000-04-29 23:57:08 +1000313 Key *private;
314 Key *public;
315 int type = dsa_mode ? KEY_DSA : KEY_RSA;
Damien Miller10f6f6b1999-11-17 17:29:08 +1100316
Damien Miller95def091999-11-25 00:26:21 +1100317 if (!have_identity)
318 ask_filename(pw, "Enter file in which the key is");
Damien Miller95def091999-11-25 00:26:21 +1100319 if (stat(identity_file, &st) < 0) {
320 perror(identity_file);
321 exit(1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000322 }
Damien Millereba71ba2000-04-29 23:57:08 +1000323
324 if (type == KEY_RSA) {
325 /* XXX this works currently only for RSA */
326 public = key_new(type);
327 if (!load_public_key(identity_file, public, NULL)) {
328 printf("%s is not a valid key file.\n", identity_file);
329 exit(1);
330 }
331 /* Clear the public key since we are just about to load the whole file. */
332 key_free(public);
Damien Miller95def091999-11-25 00:26:21 +1100333 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000334
Damien Miller95def091999-11-25 00:26:21 +1100335 /* Try to load the file with empty passphrase. */
Damien Millereba71ba2000-04-29 23:57:08 +1000336 private = key_new(type);
337 if (!load_private_key(identity_file, "", private, &comment)) {
Damien Miller95def091999-11-25 00:26:21 +1100338 if (identity_passphrase)
339 old_passphrase = xstrdup(identity_passphrase);
340 else
341 old_passphrase = read_passphrase("Enter old passphrase: ", 1);
Damien Millereba71ba2000-04-29 23:57:08 +1000342 if (!load_private_key(identity_file, old_passphrase, private, &comment)) {
Damien Miller95def091999-11-25 00:26:21 +1100343 memset(old_passphrase, 0, strlen(old_passphrase));
344 xfree(old_passphrase);
345 printf("Bad passphrase.\n");
346 exit(1);
347 }
Damien Miller95def091999-11-25 00:26:21 +1100348 memset(old_passphrase, 0, strlen(old_passphrase));
349 xfree(old_passphrase);
350 }
351 printf("Key has comment '%s'\n", comment);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000352
Damien Miller95def091999-11-25 00:26:21 +1100353 /* Ask the new passphrase (twice). */
354 if (identity_new_passphrase) {
355 passphrase1 = xstrdup(identity_new_passphrase);
356 passphrase2 = NULL;
357 } else {
358 passphrase1 =
359 read_passphrase("Enter new passphrase (empty for no passphrase): ", 1);
360 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
361
362 /* Verify that they are the same. */
363 if (strcmp(passphrase1, passphrase2) != 0) {
364 memset(passphrase1, 0, strlen(passphrase1));
365 memset(passphrase2, 0, strlen(passphrase2));
366 xfree(passphrase1);
367 xfree(passphrase2);
368 printf("Pass phrases do not match. Try again.\n");
369 exit(1);
370 }
371 /* Destroy the other copy. */
372 memset(passphrase2, 0, strlen(passphrase2));
373 xfree(passphrase2);
374 }
375
376 /* Save the file using the new passphrase. */
Damien Millereba71ba2000-04-29 23:57:08 +1000377 if (!save_private_key(identity_file, passphrase1, private, comment)) {
Damien Miller95def091999-11-25 00:26:21 +1100378 printf("Saving the key failed: %s: %s.\n",
379 identity_file, strerror(errno));
380 memset(passphrase1, 0, strlen(passphrase1));
381 xfree(passphrase1);
Damien Millereba71ba2000-04-29 23:57:08 +1000382 key_free(private);
Damien Miller95def091999-11-25 00:26:21 +1100383 xfree(comment);
384 exit(1);
385 }
386 /* Destroy the passphrase and the copy of the key in memory. */
387 memset(passphrase1, 0, strlen(passphrase1));
388 xfree(passphrase1);
Damien Millereba71ba2000-04-29 23:57:08 +1000389 key_free(private); /* Destroys contents */
Damien Miller95def091999-11-25 00:26:21 +1100390 xfree(comment);
391
392 printf("Your identification has been saved with the new passphrase.\n");
393 exit(0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000394}
395
Damien Miller95def091999-11-25 00:26:21 +1100396/*
397 * Change the comment of a private key file.
398 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000399void
400do_change_comment(struct passwd *pw)
401{
Damien Miller95def091999-11-25 00:26:21 +1100402 char new_comment[1024], *comment;
Damien Millereba71ba2000-04-29 23:57:08 +1000403 Key *private;
404 Key *public;
Damien Miller95def091999-11-25 00:26:21 +1100405 char *passphrase;
406 struct stat st;
407 FILE *f;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000408
Damien Miller95def091999-11-25 00:26:21 +1100409 if (!have_identity)
410 ask_filename(pw, "Enter file in which the key is");
Damien Miller95def091999-11-25 00:26:21 +1100411 if (stat(identity_file, &st) < 0) {
412 perror(identity_file);
413 exit(1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000414 }
Damien Miller5428f641999-11-25 11:54:57 +1100415 /*
416 * Try to load the public key from the file the verify that it is
417 * readable and of the proper format.
418 */
Damien Millereba71ba2000-04-29 23:57:08 +1000419 public = key_new(KEY_RSA);
420 if (!load_public_key(identity_file, public, NULL)) {
Damien Miller95def091999-11-25 00:26:21 +1100421 printf("%s is not a valid key file.\n", identity_file);
422 exit(1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000423 }
Damien Miller5428f641999-11-25 11:54:57 +1100424
Damien Millereba71ba2000-04-29 23:57:08 +1000425 private = key_new(KEY_RSA);
426 if (load_private_key(identity_file, "", private, &comment))
Damien Miller95def091999-11-25 00:26:21 +1100427 passphrase = xstrdup("");
428 else {
Damien Miller95def091999-11-25 00:26:21 +1100429 if (identity_passphrase)
430 passphrase = xstrdup(identity_passphrase);
431 else if (identity_new_passphrase)
432 passphrase = xstrdup(identity_new_passphrase);
433 else
434 passphrase = read_passphrase("Enter passphrase: ", 1);
435 /* Try to load using the passphrase. */
Damien Millereba71ba2000-04-29 23:57:08 +1000436 if (!load_private_key(identity_file, passphrase, private, &comment)) {
Damien Miller95def091999-11-25 00:26:21 +1100437 memset(passphrase, 0, strlen(passphrase));
438 xfree(passphrase);
439 printf("Bad passphrase.\n");
440 exit(1);
441 }
442 }
443 printf("Key now has comment '%s'\n", comment);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000444
Damien Miller95def091999-11-25 00:26:21 +1100445 if (identity_comment) {
446 strlcpy(new_comment, identity_comment, sizeof(new_comment));
447 } else {
448 printf("Enter new comment: ");
449 fflush(stdout);
450 if (!fgets(new_comment, sizeof(new_comment), stdin)) {
451 memset(passphrase, 0, strlen(passphrase));
Damien Millereba71ba2000-04-29 23:57:08 +1000452 key_free(private);
Damien Miller95def091999-11-25 00:26:21 +1100453 exit(1);
454 }
Damien Miller95def091999-11-25 00:26:21 +1100455 if (strchr(new_comment, '\n'))
456 *strchr(new_comment, '\n') = 0;
457 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000458
Damien Miller95def091999-11-25 00:26:21 +1100459 /* Save the file using the new passphrase. */
Damien Millereba71ba2000-04-29 23:57:08 +1000460 if (!save_private_key(identity_file, passphrase, private, new_comment)) {
Damien Miller95def091999-11-25 00:26:21 +1100461 printf("Saving the key failed: %s: %s.\n",
462 identity_file, strerror(errno));
463 memset(passphrase, 0, strlen(passphrase));
464 xfree(passphrase);
Damien Millereba71ba2000-04-29 23:57:08 +1000465 key_free(private);
Damien Miller95def091999-11-25 00:26:21 +1100466 xfree(comment);
467 exit(1);
468 }
Damien Miller95def091999-11-25 00:26:21 +1100469 memset(passphrase, 0, strlen(passphrase));
470 xfree(passphrase);
Damien Millereba71ba2000-04-29 23:57:08 +1000471 key_free(private);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000472
Damien Miller95def091999-11-25 00:26:21 +1100473 strlcat(identity_file, ".pub", sizeof(identity_file));
474 f = fopen(identity_file, "w");
475 if (!f) {
476 printf("Could not save your public key in %s\n", identity_file);
477 exit(1);
478 }
Damien Millereba71ba2000-04-29 23:57:08 +1000479 if (!key_write(public, f))
480 fprintf(stderr, "write key failed");
481 key_free(public);
482 fprintf(f, " %s\n", new_comment);
Damien Miller95def091999-11-25 00:26:21 +1100483 fclose(f);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000484
Damien Miller95def091999-11-25 00:26:21 +1100485 xfree(comment);
486
487 printf("The comment in your key file has been changed.\n");
488 exit(0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000489}
490
Damien Miller431f66b1999-11-21 18:31:57 +1100491void
492usage(void)
493{
Damien Miller95def091999-11-25 00:26:21 +1100494 printf("ssh-keygen version %s\n", SSH_VERSION);
Damien Millereba71ba2000-04-29 23:57:08 +1000495 printf("Usage: %s [-b bits] [-p] [-c] [-l] [-x] [-X] [-y] [-f file] [-P pass] [-N new-pass] [-C comment]\n", __progname);
Damien Miller95def091999-11-25 00:26:21 +1100496 exit(1);
Damien Miller431f66b1999-11-21 18:31:57 +1100497}
498
Damien Miller95def091999-11-25 00:26:21 +1100499/*
500 * Main program for key management.
501 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000502int
503main(int ac, char **av)
504{
Damien Miller95def091999-11-25 00:26:21 +1100505 char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
506 struct passwd *pw;
Damien Miller95def091999-11-25 00:26:21 +1100507 int opt;
508 struct stat st;
509 FILE *f;
Damien Millereba71ba2000-04-29 23:57:08 +1000510 Key *private;
511 Key *public;
Damien Miller95def091999-11-25 00:26:21 +1100512 extern int optind;
513 extern char *optarg;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000514
Damien Millereba71ba2000-04-29 23:57:08 +1000515 OpenSSL_add_all_algorithms();
516
Damien Miller5428f641999-11-25 11:54:57 +1100517 /* we need this for the home * directory. */
Damien Miller95def091999-11-25 00:26:21 +1100518 pw = getpwuid(getuid());
519 if (!pw) {
520 printf("You don't exist, go away!\n");
521 exit(1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000522 }
Damien Millereba71ba2000-04-29 23:57:08 +1000523 if (gethostname(hostname, sizeof(hostname)) < 0) {
524 perror("gethostname");
525 exit(1);
526 }
Damien Miller5428f641999-11-25 11:54:57 +1100527
Damien Millereba71ba2000-04-29 23:57:08 +1000528 while ((opt = getopt(ac, av, "dqpclRxXyb:f:P:N:C:")) != EOF) {
Damien Miller95def091999-11-25 00:26:21 +1100529 switch (opt) {
530 case 'b':
531 bits = atoi(optarg);
532 if (bits < 512 || bits > 32768) {
533 printf("Bits has bad value.\n");
534 exit(1);
535 }
536 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000537
Damien Miller95def091999-11-25 00:26:21 +1100538 case 'l':
539 print_fingerprint = 1;
540 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000541
Damien Miller95def091999-11-25 00:26:21 +1100542 case 'p':
543 change_passphrase = 1;
544 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000545
Damien Miller95def091999-11-25 00:26:21 +1100546 case 'c':
547 change_comment = 1;
548 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000549
Damien Miller95def091999-11-25 00:26:21 +1100550 case 'f':
551 strlcpy(identity_file, optarg, sizeof(identity_file));
552 have_identity = 1;
553 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000554
Damien Miller95def091999-11-25 00:26:21 +1100555 case 'P':
556 identity_passphrase = optarg;
557 break;
558
559 case 'N':
560 identity_new_passphrase = optarg;
561 break;
562
563 case 'C':
564 identity_comment = optarg;
565 break;
566
567 case 'q':
568 quiet = 1;
569 break;
570
Damien Millereba71ba2000-04-29 23:57:08 +1000571 case 'R':
572 if (rsa_alive() == 0)
573 exit(1);
574 else
575 exit(0);
576 break;
577
578 case 'x':
579 convert_to_ssh2 = 1;
580 break;
581
582 case 'X':
583 convert_from_ssh2 = 1;
584 break;
585
586 case 'y':
587 print_public = 1;
588 break;
589
590 case 'd':
591 dsa_mode = 1;
592 break;
593
Damien Miller95def091999-11-25 00:26:21 +1100594 case '?':
595 default:
596 usage();
597 }
598 }
599 if (optind < ac) {
600 printf("Too many arguments.\n");
601 usage();
602 }
603 if (change_passphrase && change_comment) {
604 printf("Can only have one of -p and -c.\n");
605 usage();
606 }
Damien Millereba71ba2000-04-29 23:57:08 +1000607 /* check if RSA support is needed and exists */
608 if (dsa_mode == 0 && rsa_alive() == 0) {
609 fprintf(stderr,
610 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
611 __progname);
612 exit(1);
613 }
Damien Miller95def091999-11-25 00:26:21 +1100614 if (print_fingerprint)
615 do_fingerprint(pw);
Damien Miller95def091999-11-25 00:26:21 +1100616 if (change_passphrase)
617 do_change_passphrase(pw);
Damien Miller95def091999-11-25 00:26:21 +1100618 if (change_comment)
619 do_change_comment(pw);
Damien Millereba71ba2000-04-29 23:57:08 +1000620 if (convert_to_ssh2)
621 do_convert_to_ssh2(pw);
622 if (convert_from_ssh2)
623 do_convert_from_ssh2(pw);
624 if (print_public)
625 do_print_public(pw);
Damien Miller95def091999-11-25 00:26:21 +1100626
627 arc4random_stir();
628
Damien Millereba71ba2000-04-29 23:57:08 +1000629 if (dsa_mode != 0) {
630 if (!quiet)
631 printf("Generating DSA parameter and key.\n");
632 public = private = dsa_generate_key(bits);
633 if (private == NULL) {
634 fprintf(stderr, "dsa_generate_keys failed");
635 exit(1);
636 }
637 } else {
638 if (quiet)
639 rsa_set_verbose(0);
640 /* Generate the rsa key pair. */
641 public = key_new(KEY_RSA);
642 private = key_new(KEY_RSA);
643 rsa_generate_key(private->rsa, public->rsa, bits);
644 }
Damien Miller95def091999-11-25 00:26:21 +1100645
646 if (!have_identity)
647 ask_filename(pw, "Enter file in which to save the key");
648
649 /* Create ~/.ssh directory if it doesn\'t already exist. */
650 snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, SSH_USER_DIR);
651 if (strstr(identity_file, dotsshdir) != NULL &&
652 stat(dotsshdir, &st) < 0) {
653 if (mkdir(dotsshdir, 0755) < 0)
654 error("Could not create directory '%s'.", dotsshdir);
655 else if (!quiet)
656 printf("Created directory '%s'.\n", dotsshdir);
657 }
658 /* If the file already exists, ask the user to confirm. */
659 if (stat(identity_file, &st) >= 0) {
660 char yesno[3];
661 printf("%s already exists.\n", identity_file);
662 printf("Overwrite (y/n)? ");
663 fflush(stdout);
664 if (fgets(yesno, sizeof(yesno), stdin) == NULL)
665 exit(1);
666 if (yesno[0] != 'y' && yesno[0] != 'Y')
667 exit(1);
668 }
669 /* Ask for a passphrase (twice). */
670 if (identity_passphrase)
671 passphrase1 = xstrdup(identity_passphrase);
672 else if (identity_new_passphrase)
673 passphrase1 = xstrdup(identity_new_passphrase);
674 else {
675passphrase_again:
676 passphrase1 =
677 read_passphrase("Enter passphrase (empty for no passphrase): ", 1);
678 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
679 if (strcmp(passphrase1, passphrase2) != 0) {
680 /* The passphrases do not match. Clear them and retry. */
681 memset(passphrase1, 0, strlen(passphrase1));
682 memset(passphrase2, 0, strlen(passphrase2));
683 xfree(passphrase1);
684 xfree(passphrase2);
685 printf("Passphrases do not match. Try again.\n");
686 goto passphrase_again;
687 }
688 /* Clear the other copy of the passphrase. */
689 memset(passphrase2, 0, strlen(passphrase2));
690 xfree(passphrase2);
691 }
692
Damien Miller95def091999-11-25 00:26:21 +1100693 if (identity_comment) {
694 strlcpy(comment, identity_comment, sizeof(comment));
695 } else {
Damien Miller4af51302000-04-16 11:18:38 +1000696 /* Create default commend field for the passphrase. */
Damien Miller95def091999-11-25 00:26:21 +1100697 snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
698 }
699
700 /* Save the key with the given passphrase and comment. */
Damien Millereba71ba2000-04-29 23:57:08 +1000701 if (!save_private_key(identity_file, passphrase1, private, comment)) {
Damien Miller95def091999-11-25 00:26:21 +1100702 printf("Saving the key failed: %s: %s.\n",
Damien Millereba71ba2000-04-29 23:57:08 +1000703 identity_file, strerror(errno));
Damien Miller95def091999-11-25 00:26:21 +1100704 memset(passphrase1, 0, strlen(passphrase1));
705 xfree(passphrase1);
706 exit(1);
707 }
708 /* Clear the passphrase. */
709 memset(passphrase1, 0, strlen(passphrase1));
710 xfree(passphrase1);
711
712 /* Clear the private key and the random number generator. */
Damien Millereba71ba2000-04-29 23:57:08 +1000713 if (private != public) {
714 key_free(private);
715 }
Damien Miller95def091999-11-25 00:26:21 +1100716 arc4random_stir();
717
718 if (!quiet)
719 printf("Your identification has been saved in %s.\n", identity_file);
720
Damien Miller95def091999-11-25 00:26:21 +1100721 strlcat(identity_file, ".pub", sizeof(identity_file));
722 f = fopen(identity_file, "w");
723 if (!f) {
724 printf("Could not save your public key in %s\n", identity_file);
725 exit(1);
726 }
Damien Millereba71ba2000-04-29 23:57:08 +1000727 if (!key_write(public, f))
728 fprintf(stderr, "write key failed");
729 fprintf(f, " %s\n", comment);
Damien Miller95def091999-11-25 00:26:21 +1100730 fclose(f);
731
732 if (!quiet) {
Damien Millereba71ba2000-04-29 23:57:08 +1000733 printf("Your public key has been saved in %s.\n",
734 identity_file);
Damien Miller95def091999-11-25 00:26:21 +1100735 printf("The key fingerprint is:\n");
Damien Millereba71ba2000-04-29 23:57:08 +1000736 printf("%s %s\n", key_fingerprint(public), comment);
Damien Miller95def091999-11-25 00:26:21 +1100737 }
Damien Millereba71ba2000-04-29 23:57:08 +1000738
739 key_free(public);
Damien Miller95def091999-11-25 00:26:21 +1100740 exit(0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000741}