blob: a2599dab9f35fa747f892e125f39f37a66daf5dc [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 Millere247cc42000-05-07 12:03:14 +100010RCSID("$Id: ssh-keygen.c,v 1.17 2000/05/07 02:03:19 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 */
Damien Miller70fb6712000-05-01 20:59:50 +100069static const char *__progname = "ssh-keygen";
Damien Miller95def091999-11-25 00:26:21 +110070#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",
Damien Millere247cc42000-05-07 12:03:14 +100079 pw->pw_dir,
80 dsa_mode ? SSH_CLIENT_ID_DSA: SSH_CLIENT_IDENTITY);
Damien Miller95def091999-11-25 00:26:21 +110081 printf("%s (%s): ", prompt, identity_file);
82 fflush(stdout);
83 if (fgets(buf, sizeof(buf), stdin) == NULL)
84 exit(1);
85 if (strchr(buf, '\n'))
86 *strchr(buf, '\n') = 0;
87 if (strcmp(buf, "") != 0)
88 strlcpy(identity_file, buf, sizeof(identity_file));
89 have_identity = 1;
Damien Miller10f6f6b1999-11-17 17:29:08 +110090}
Damien Millerd4a8b7e1999-10-27 13:42:43 +100091
Damien Millereba71ba2000-04-29 23:57:08 +100092int
93try_load_key(char *filename, Key *k)
94{
95 int success = 1;
96 if (!load_private_key(filename, "", k, NULL)) {
97 char *pass = read_passphrase("Enter passphrase: ", 1);
98 if (!load_private_key(filename, pass, k, NULL)) {
99 success = 0;
100 }
101 memset(pass, 0, strlen(pass));
102 xfree(pass);
103 }
104 return success;
105}
106
107#define SSH_COM_MAGIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
108#define SSH_COM_MAGIC_END "---- END SSH2 PUBLIC KEY ----"
109
110void
111do_convert_to_ssh2(struct passwd *pw)
112{
113 Key *k;
114 int len;
115 unsigned char *blob;
116 struct stat st;
117
118 if (!have_identity)
119 ask_filename(pw, "Enter file in which the key is");
120 if (stat(identity_file, &st) < 0) {
121 perror(identity_file);
122 exit(1);
123 }
124 k = key_new(KEY_DSA);
125 if (!try_load_key(identity_file, k)) {
126 fprintf(stderr, "load failed\n");
127 exit(1);
128 }
129 dsa_make_key_blob(k, &blob, &len);
130 fprintf(stdout, SSH_COM_MAGIC_BEGIN "\n");
131 fprintf(stdout,
132 "Comment: \"%d-bit DSA, converted from openssh by %s@%s\"\n",
133 BN_num_bits(k->dsa->p),
134 pw->pw_name, hostname);
135 dump_base64(stdout, blob, len);
136 fprintf(stdout, SSH_COM_MAGIC_END "\n");
137 key_free(k);
138 xfree(blob);
139 exit(0);
140}
141
142void
143do_convert_from_ssh2(struct passwd *pw)
144{
145 Key *k;
146 int blen;
147 char line[1024], *p;
148 char blob[8096];
149 char encoded[8096];
150 struct stat st;
151 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)) {
166 if (strncmp(line, "----", 4) == 0 ||
167 strstr(line, ": ") != NULL) {
168 fprintf(stderr, "ignore: %s", line);
169 continue;
170 }
171 if (!(p = strchr(line, '\n'))) {
172 fprintf(stderr, "input line too long.\n");
173 exit(1);
174 }
175 *p = '\0';
176 strlcat(encoded, line, sizeof(encoded));
177 }
178 blen = uudecode(encoded, (unsigned char *)blob, sizeof(blob));
179 if (blen < 0) {
180 fprintf(stderr, "uudecode failed.\n");
181 exit(1);
182 }
183 k = dsa_key_from_blob(blob, blen);
184 if (!key_write(k, stdout))
185 fprintf(stderr, "key_write failed");
186 key_free(k);
187 fprintf(stdout, "\n");
188 fclose(fp);
189 exit(0);
190}
191
192void
193do_print_public(struct passwd *pw)
194{
195 Key *k;
196 int len;
197 unsigned char *blob;
198 struct stat st;
199
200 if (!have_identity)
201 ask_filename(pw, "Enter file in which the key is");
202 if (stat(identity_file, &st) < 0) {
203 perror(identity_file);
204 exit(1);
205 }
206 k = key_new(KEY_DSA);
207 if (!try_load_key(identity_file, k)) {
208 fprintf(stderr, "load failed\n");
209 exit(1);
210 }
211 dsa_make_key_blob(k, &blob, &len);
212 if (!key_write(k, stdout))
213 fprintf(stderr, "key_write failed");
214 key_free(k);
215 xfree(blob);
216 fprintf(stdout, "\n");
217 exit(0);
218}
219
Damien Miller10f6f6b1999-11-17 17:29:08 +1100220void
221do_fingerprint(struct passwd *pw)
222{
Damien Miller98c7ad62000-03-09 21:27:49 +1100223 FILE *f;
224 BIGNUM *e, *n;
Damien Millereba71ba2000-04-29 23:57:08 +1000225 Key *public;
Damien Miller98c7ad62000-03-09 21:27:49 +1100226 char *comment = NULL, *cp, *ep, line[16*1024];
227 int i, skip = 0, num = 1, invalid = 1;
Damien Miller7684ee12000-03-17 23:40:15 +1100228 unsigned int ignore;
Damien Miller95def091999-11-25 00:26:21 +1100229 struct stat st;
Damien Miller10f6f6b1999-11-17 17:29:08 +1100230
Damien Miller95def091999-11-25 00:26:21 +1100231 if (!have_identity)
232 ask_filename(pw, "Enter file in which the key is");
233 if (stat(identity_file, &st) < 0) {
234 perror(identity_file);
235 exit(1);
236 }
Damien Millereba71ba2000-04-29 23:57:08 +1000237 public = key_new(KEY_RSA);
238 if (load_public_key(identity_file, public, &comment)) {
239 printf("%d %s %s\n", BN_num_bits(public->rsa->n),
240 key_fingerprint(public), comment);
241 key_free(public);
Damien Miller98c7ad62000-03-09 21:27:49 +1100242 exit(0);
243 }
Damien Millereba71ba2000-04-29 23:57:08 +1000244 key_free(public);
Damien Miller98c7ad62000-03-09 21:27:49 +1100245
Damien Millereba71ba2000-04-29 23:57:08 +1000246 /* XXX */
Damien Miller98c7ad62000-03-09 21:27:49 +1100247 f = fopen(identity_file, "r");
248 if (f != NULL) {
Damien Miller95def091999-11-25 00:26:21 +1100249 n = BN_new();
250 e = BN_new();
Damien Miller98c7ad62000-03-09 21:27:49 +1100251 while (fgets(line, sizeof(line), f)) {
252 i = strlen(line) - 1;
253 if (line[i] != '\n') {
254 error("line %d too long: %.40s...", num, line);
255 skip = 1;
256 continue;
Damien Miller95def091999-11-25 00:26:21 +1100257 }
Damien Miller98c7ad62000-03-09 21:27:49 +1100258 num++;
259 if (skip) {
260 skip = 0;
261 continue;
262 }
263 line[i] = '\0';
264
265 /* Skip leading whitespace, empty and comment lines. */
266 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
267 ;
268 if (!*cp || *cp == '\n' || *cp == '#')
269 continue ;
270 i = strtol(cp, &ep, 10);
271 if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
272 int quoted = 0;
273 comment = cp;
274 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
275 if (*cp == '\\' && cp[1] == '"')
276 cp++; /* Skip both */
277 else if (*cp == '"')
278 quoted = !quoted;
279 }
280 if (!*cp)
281 continue;
282 *cp++ = '\0';
283 }
284 ep = cp;
Damien Miller7684ee12000-03-17 23:40:15 +1100285 if (auth_rsa_read_key(&cp, &ignore, e, n)) {
Damien Miller98c7ad62000-03-09 21:27:49 +1100286 invalid = 0;
287 comment = *cp ? cp : comment;
288 printf("%d %s %s\n", BN_num_bits(n),
289 fingerprint(e, n),
290 comment ? comment : "no comment");
291 }
Damien Miller95def091999-11-25 00:26:21 +1100292 }
Damien Miller98c7ad62000-03-09 21:27:49 +1100293 BN_free(e);
294 BN_free(n);
295 fclose(f);
Damien Miller95def091999-11-25 00:26:21 +1100296 }
Damien Miller98c7ad62000-03-09 21:27:49 +1100297 if (invalid) {
298 printf("%s is not a valid key file.\n", identity_file);
299 exit(1);
300 }
Damien Miller95def091999-11-25 00:26:21 +1100301 exit(0);
Damien Miller10f6f6b1999-11-17 17:29:08 +1100302}
303
Damien Miller95def091999-11-25 00:26:21 +1100304/*
305 * Perform changing a passphrase. The argument is the passwd structure
306 * for the current user.
307 */
Damien Miller10f6f6b1999-11-17 17:29:08 +1100308void
309do_change_passphrase(struct passwd *pw)
310{
Damien Miller95def091999-11-25 00:26:21 +1100311 char *comment;
312 char *old_passphrase, *passphrase1, *passphrase2;
313 struct stat st;
Damien Millereba71ba2000-04-29 23:57:08 +1000314 Key *private;
315 Key *public;
316 int type = dsa_mode ? KEY_DSA : KEY_RSA;
Damien Miller10f6f6b1999-11-17 17:29:08 +1100317
Damien Miller95def091999-11-25 00:26:21 +1100318 if (!have_identity)
319 ask_filename(pw, "Enter file in which the key is");
Damien Miller95def091999-11-25 00:26:21 +1100320 if (stat(identity_file, &st) < 0) {
321 perror(identity_file);
322 exit(1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000323 }
Damien Millereba71ba2000-04-29 23:57:08 +1000324
325 if (type == KEY_RSA) {
326 /* XXX this works currently only for RSA */
327 public = key_new(type);
328 if (!load_public_key(identity_file, public, NULL)) {
329 printf("%s is not a valid key file.\n", identity_file);
330 exit(1);
331 }
332 /* Clear the public key since we are just about to load the whole file. */
333 key_free(public);
Damien Miller95def091999-11-25 00:26:21 +1100334 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000335
Damien Miller95def091999-11-25 00:26:21 +1100336 /* Try to load the file with empty passphrase. */
Damien Millereba71ba2000-04-29 23:57:08 +1000337 private = key_new(type);
338 if (!load_private_key(identity_file, "", private, &comment)) {
Damien Miller95def091999-11-25 00:26:21 +1100339 if (identity_passphrase)
340 old_passphrase = xstrdup(identity_passphrase);
341 else
342 old_passphrase = read_passphrase("Enter old passphrase: ", 1);
Damien Millereba71ba2000-04-29 23:57:08 +1000343 if (!load_private_key(identity_file, old_passphrase, private, &comment)) {
Damien Miller95def091999-11-25 00:26:21 +1100344 memset(old_passphrase, 0, strlen(old_passphrase));
345 xfree(old_passphrase);
346 printf("Bad passphrase.\n");
347 exit(1);
348 }
Damien Miller95def091999-11-25 00:26:21 +1100349 memset(old_passphrase, 0, strlen(old_passphrase));
350 xfree(old_passphrase);
351 }
352 printf("Key has comment '%s'\n", comment);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000353
Damien Miller95def091999-11-25 00:26:21 +1100354 /* Ask the new passphrase (twice). */
355 if (identity_new_passphrase) {
356 passphrase1 = xstrdup(identity_new_passphrase);
357 passphrase2 = NULL;
358 } else {
359 passphrase1 =
360 read_passphrase("Enter new passphrase (empty for no passphrase): ", 1);
361 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
362
363 /* Verify that they are the same. */
364 if (strcmp(passphrase1, passphrase2) != 0) {
365 memset(passphrase1, 0, strlen(passphrase1));
366 memset(passphrase2, 0, strlen(passphrase2));
367 xfree(passphrase1);
368 xfree(passphrase2);
369 printf("Pass phrases do not match. Try again.\n");
370 exit(1);
371 }
372 /* Destroy the other copy. */
373 memset(passphrase2, 0, strlen(passphrase2));
374 xfree(passphrase2);
375 }
376
377 /* Save the file using the new passphrase. */
Damien Millereba71ba2000-04-29 23:57:08 +1000378 if (!save_private_key(identity_file, passphrase1, private, comment)) {
Damien Miller95def091999-11-25 00:26:21 +1100379 printf("Saving the key failed: %s: %s.\n",
380 identity_file, strerror(errno));
381 memset(passphrase1, 0, strlen(passphrase1));
382 xfree(passphrase1);
Damien Millereba71ba2000-04-29 23:57:08 +1000383 key_free(private);
Damien Miller95def091999-11-25 00:26:21 +1100384 xfree(comment);
385 exit(1);
386 }
387 /* Destroy the passphrase and the copy of the key in memory. */
388 memset(passphrase1, 0, strlen(passphrase1));
389 xfree(passphrase1);
Damien Millereba71ba2000-04-29 23:57:08 +1000390 key_free(private); /* Destroys contents */
Damien Miller95def091999-11-25 00:26:21 +1100391 xfree(comment);
392
393 printf("Your identification has been saved with the new passphrase.\n");
394 exit(0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000395}
396
Damien Miller95def091999-11-25 00:26:21 +1100397/*
398 * Change the comment of a private key file.
399 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000400void
401do_change_comment(struct passwd *pw)
402{
Damien Miller95def091999-11-25 00:26:21 +1100403 char new_comment[1024], *comment;
Damien Millereba71ba2000-04-29 23:57:08 +1000404 Key *private;
405 Key *public;
Damien Miller95def091999-11-25 00:26:21 +1100406 char *passphrase;
407 struct stat st;
408 FILE *f;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000409
Damien Miller95def091999-11-25 00:26:21 +1100410 if (!have_identity)
411 ask_filename(pw, "Enter file in which the key is");
Damien Miller95def091999-11-25 00:26:21 +1100412 if (stat(identity_file, &st) < 0) {
413 perror(identity_file);
414 exit(1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000415 }
Damien Miller5428f641999-11-25 11:54:57 +1100416 /*
417 * Try to load the public key from the file the verify that it is
418 * readable and of the proper format.
419 */
Damien Millereba71ba2000-04-29 23:57:08 +1000420 public = key_new(KEY_RSA);
421 if (!load_public_key(identity_file, public, NULL)) {
Damien Miller95def091999-11-25 00:26:21 +1100422 printf("%s is not a valid key file.\n", identity_file);
423 exit(1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000424 }
Damien Miller5428f641999-11-25 11:54:57 +1100425
Damien Millereba71ba2000-04-29 23:57:08 +1000426 private = key_new(KEY_RSA);
427 if (load_private_key(identity_file, "", private, &comment))
Damien Miller95def091999-11-25 00:26:21 +1100428 passphrase = xstrdup("");
429 else {
Damien Miller95def091999-11-25 00:26:21 +1100430 if (identity_passphrase)
431 passphrase = xstrdup(identity_passphrase);
432 else if (identity_new_passphrase)
433 passphrase = xstrdup(identity_new_passphrase);
434 else
435 passphrase = read_passphrase("Enter passphrase: ", 1);
436 /* Try to load using the passphrase. */
Damien Millereba71ba2000-04-29 23:57:08 +1000437 if (!load_private_key(identity_file, passphrase, private, &comment)) {
Damien Miller95def091999-11-25 00:26:21 +1100438 memset(passphrase, 0, strlen(passphrase));
439 xfree(passphrase);
440 printf("Bad passphrase.\n");
441 exit(1);
442 }
443 }
444 printf("Key now has comment '%s'\n", comment);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000445
Damien Miller95def091999-11-25 00:26:21 +1100446 if (identity_comment) {
447 strlcpy(new_comment, identity_comment, sizeof(new_comment));
448 } else {
449 printf("Enter new comment: ");
450 fflush(stdout);
451 if (!fgets(new_comment, sizeof(new_comment), stdin)) {
452 memset(passphrase, 0, strlen(passphrase));
Damien Millereba71ba2000-04-29 23:57:08 +1000453 key_free(private);
Damien Miller95def091999-11-25 00:26:21 +1100454 exit(1);
455 }
Damien Miller95def091999-11-25 00:26:21 +1100456 if (strchr(new_comment, '\n'))
457 *strchr(new_comment, '\n') = 0;
458 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000459
Damien Miller95def091999-11-25 00:26:21 +1100460 /* Save the file using the new passphrase. */
Damien Millereba71ba2000-04-29 23:57:08 +1000461 if (!save_private_key(identity_file, passphrase, private, new_comment)) {
Damien Miller95def091999-11-25 00:26:21 +1100462 printf("Saving the key failed: %s: %s.\n",
463 identity_file, strerror(errno));
464 memset(passphrase, 0, strlen(passphrase));
465 xfree(passphrase);
Damien Millereba71ba2000-04-29 23:57:08 +1000466 key_free(private);
Damien Miller95def091999-11-25 00:26:21 +1100467 xfree(comment);
468 exit(1);
469 }
Damien Miller95def091999-11-25 00:26:21 +1100470 memset(passphrase, 0, strlen(passphrase));
471 xfree(passphrase);
Damien Millereba71ba2000-04-29 23:57:08 +1000472 key_free(private);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000473
Damien Miller95def091999-11-25 00:26:21 +1100474 strlcat(identity_file, ".pub", sizeof(identity_file));
475 f = fopen(identity_file, "w");
476 if (!f) {
477 printf("Could not save your public key in %s\n", identity_file);
478 exit(1);
479 }
Damien Millereba71ba2000-04-29 23:57:08 +1000480 if (!key_write(public, f))
481 fprintf(stderr, "write key failed");
482 key_free(public);
483 fprintf(f, " %s\n", new_comment);
Damien Miller95def091999-11-25 00:26:21 +1100484 fclose(f);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000485
Damien Miller95def091999-11-25 00:26:21 +1100486 xfree(comment);
487
488 printf("The comment in your key file has been changed.\n");
489 exit(0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000490}
491
Damien Miller431f66b1999-11-21 18:31:57 +1100492void
493usage(void)
494{
Damien Millere247cc42000-05-07 12:03:14 +1000495 printf("Usage: %s [-lpqxXydc] [-b bits] [-f file] [-C comment] [-N new-pass] [-P pass]\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}