]> andersk Git - openssh.git/blame - ssh-keygen.c
- More reformatting merged from OpenBSD CVS
[openssh.git] / ssh-keygen.c
CommitLineData
8efc0c15 1/*
5260325f 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 */
8efc0c15 8
9#include "includes.h"
10RCSID("$Id$");
11
12#include "rsa.h"
13#include "ssh.h"
14#include "xmalloc.h"
f095fcc7 15#include "fingerprint.h"
8efc0c15 16
17/* Generated private key. */
18RSA *private_key;
19
20/* Generated public key. */
21RSA *public_key;
22
aa3378df 23/* Number of bits in the RSA key. This value can be changed on the command line. */
8efc0c15 24int bits = 1024;
25
aa3378df 26/*
27 * Flag indicating that we just want to change the passphrase. This can be
28 * set on the command line.
29 */
8efc0c15 30int change_passphrase = 0;
31
aa3378df 32/*
33 * Flag indicating that we just want to change the comment. This can be set
34 * on the command line.
35 */
8efc0c15 36int change_comment = 0;
37
38int quiet = 0;
39
f095fcc7 40/* Flag indicating that we just want to see the key fingerprint */
41int print_fingerprint = 0;
42
5ad13cd7 43/* The identity file name, given on the command line or entered by the user. */
44char identity_file[1024];
45int have_identity = 0;
8efc0c15 46
47/* This is set to the passphrase if given on the command line. */
48char *identity_passphrase = NULL;
49
50/* This is set to the new passphrase if given on the command line. */
51char *identity_new_passphrase = NULL;
52
53/* This is set to the new comment if given on the command line. */
54char *identity_comment = NULL;
55
5ad13cd7 56/* argv0 */
5260325f 57#ifdef HAVE___PROGNAME
5ad13cd7 58extern char *__progname;
5260325f 59#else /* HAVE___PROGNAME */
60const char *__progname = "ssh-keygen";
61#endif /* HAVE___PROGNAME */
8efc0c15 62
5ad13cd7 63void
64ask_filename(struct passwd *pw, const char *prompt)
8efc0c15 65{
5260325f 66 char buf[1024];
67 snprintf(identity_file, sizeof(identity_file), "%s/%s",
68 pw->pw_dir, SSH_CLIENT_IDENTITY);
69 printf("%s (%s): ", prompt, identity_file);
70 fflush(stdout);
71 if (fgets(buf, sizeof(buf), stdin) == NULL)
72 exit(1);
73 if (strchr(buf, '\n'))
74 *strchr(buf, '\n') = 0;
75 if (strcmp(buf, "") != 0)
76 strlcpy(identity_file, buf, sizeof(identity_file));
77 have_identity = 1;
f095fcc7 78}
8efc0c15 79
f095fcc7 80void
81do_fingerprint(struct passwd *pw)
82{
5260325f 83 char *comment;
84 RSA *public_key;
85 struct stat st;
86
87 if (!have_identity)
88 ask_filename(pw, "Enter file in which the key is");
89 if (stat(identity_file, &st) < 0) {
90 perror(identity_file);
91 exit(1);
92 }
93 public_key = RSA_new();
94 if (!load_public_key(identity_file, public_key, &comment)) {
95 char *cp, line[1024];
96 BIGNUM *e, *n;
97 int dummy, invalid = 0;
98 FILE *f = fopen(identity_file, "r");
99 n = BN_new();
100 e = BN_new();
101 if (f && fgets(line, sizeof(line), f)) {
102 cp = line;
103 line[strlen(line) - 1] = '\0';
104 if (auth_rsa_read_key(&cp, &dummy, e, n)) {
105 public_key->e = e;
106 public_key->n = n;
107 comment = xstrdup(cp ? cp : "no comment");
108 } else {
109 invalid = 1;
110 }
111 } else {
112 invalid = 1;
113 }
114 if (invalid) {
115 printf("%s is not a valid key file.\n", identity_file);
116 BN_free(e);
117 BN_free(n);
118 exit(1);
119 }
120 }
121 printf("%d %s %s\n", BN_num_bits(public_key->n),
122 fingerprint(public_key->e, public_key->n),
123 comment);
124 RSA_free(public_key);
125 exit(0);
f095fcc7 126}
127
5260325f 128/*
129 * Perform changing a passphrase. The argument is the passwd structure
130 * for the current user.
131 */
f095fcc7 132void
133do_change_passphrase(struct passwd *pw)
134{
5260325f 135 char *comment;
136 char *old_passphrase, *passphrase1, *passphrase2;
137 struct stat st;
138 RSA *private_key;
139
140 if (!have_identity)
141 ask_filename(pw, "Enter file in which the key is");
5260325f 142 if (stat(identity_file, &st) < 0) {
143 perror(identity_file);
144 exit(1);
145 }
5260325f 146 public_key = RSA_new();
147 if (!load_public_key(identity_file, public_key, NULL)) {
148 printf("%s is not a valid key file.\n", identity_file);
149 exit(1);
150 }
151 /* Clear the public key since we are just about to load the whole file. */
152 RSA_free(public_key);
153
154 /* Try to load the file with empty passphrase. */
155 private_key = RSA_new();
156 if (!load_private_key(identity_file, "", private_key, &comment)) {
5260325f 157 if (identity_passphrase)
158 old_passphrase = xstrdup(identity_passphrase);
159 else
160 old_passphrase = read_passphrase("Enter old passphrase: ", 1);
5260325f 161 if (!load_private_key(identity_file, old_passphrase, private_key, &comment)) {
162 memset(old_passphrase, 0, strlen(old_passphrase));
163 xfree(old_passphrase);
164 printf("Bad passphrase.\n");
165 exit(1);
166 }
5260325f 167 memset(old_passphrase, 0, strlen(old_passphrase));
168 xfree(old_passphrase);
169 }
170 printf("Key has comment '%s'\n", comment);
171
172 /* Ask the new passphrase (twice). */
173 if (identity_new_passphrase) {
174 passphrase1 = xstrdup(identity_new_passphrase);
175 passphrase2 = NULL;
176 } else {
177 passphrase1 =
178 read_passphrase("Enter new passphrase (empty for no passphrase): ", 1);
179 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
180
181 /* Verify that they are the same. */
182 if (strcmp(passphrase1, passphrase2) != 0) {
183 memset(passphrase1, 0, strlen(passphrase1));
184 memset(passphrase2, 0, strlen(passphrase2));
185 xfree(passphrase1);
186 xfree(passphrase2);
187 printf("Pass phrases do not match. Try again.\n");
188 exit(1);
189 }
190 /* Destroy the other copy. */
191 memset(passphrase2, 0, strlen(passphrase2));
192 xfree(passphrase2);
8efc0c15 193 }
8efc0c15 194
5260325f 195 /* Save the file using the new passphrase. */
196 if (!save_private_key(identity_file, passphrase1, private_key, comment)) {
197 printf("Saving the key failed: %s: %s.\n",
198 identity_file, strerror(errno));
199 memset(passphrase1, 0, strlen(passphrase1));
200 xfree(passphrase1);
201 RSA_free(private_key);
202 xfree(comment);
203 exit(1);
204 }
205 /* Destroy the passphrase and the copy of the key in memory. */
206 memset(passphrase1, 0, strlen(passphrase1));
207 xfree(passphrase1);
208 RSA_free(private_key); /* Destroys contents */
209 xfree(comment);
210
211 printf("Your identification has been saved with the new passphrase.\n");
212 exit(0);
213}
8efc0c15 214
5260325f 215/*
216 * Change the comment of a private key file.
217 */
8efc0c15 218void
219do_change_comment(struct passwd *pw)
220{
5260325f 221 char new_comment[1024], *comment;
222 RSA *private_key;
223 char *passphrase;
224 struct stat st;
225 FILE *f;
226 char *tmpbuf;
227
228 if (!have_identity)
229 ask_filename(pw, "Enter file in which the key is");
5260325f 230 if (stat(identity_file, &st) < 0) {
231 perror(identity_file);
232 exit(1);
233 }
aa3378df 234 /*
235 * Try to load the public key from the file the verify that it is
236 * readable and of the proper format.
237 */
5260325f 238 public_key = RSA_new();
239 if (!load_public_key(identity_file, public_key, NULL)) {
240 printf("%s is not a valid key file.\n", identity_file);
241 exit(1);
8efc0c15 242 }
5260325f 243 private_key = RSA_new();
aa3378df 244
5260325f 245 if (load_private_key(identity_file, "", private_key, &comment))
246 passphrase = xstrdup("");
247 else {
5260325f 248 if (identity_passphrase)
249 passphrase = xstrdup(identity_passphrase);
250 else if (identity_new_passphrase)
251 passphrase = xstrdup(identity_new_passphrase);
252 else
253 passphrase = read_passphrase("Enter passphrase: ", 1);
254 /* Try to load using the passphrase. */
255 if (!load_private_key(identity_file, passphrase, private_key, &comment)) {
256 memset(passphrase, 0, strlen(passphrase));
257 xfree(passphrase);
258 printf("Bad passphrase.\n");
259 exit(1);
260 }
261 }
262 printf("Key now has comment '%s'\n", comment);
263
264 if (identity_comment) {
265 strlcpy(new_comment, identity_comment, sizeof(new_comment));
266 } else {
267 printf("Enter new comment: ");
268 fflush(stdout);
269 if (!fgets(new_comment, sizeof(new_comment), stdin)) {
270 memset(passphrase, 0, strlen(passphrase));
271 RSA_free(private_key);
272 exit(1);
273 }
5260325f 274 if (strchr(new_comment, '\n'))
275 *strchr(new_comment, '\n') = 0;
276 }
277
278 /* Save the file using the new passphrase. */
279 if (!save_private_key(identity_file, passphrase, private_key, new_comment)) {
280 printf("Saving the key failed: %s: %s.\n",
281 identity_file, strerror(errno));
282 memset(passphrase, 0, strlen(passphrase));
283 xfree(passphrase);
284 RSA_free(private_key);
285 xfree(comment);
286 exit(1);
8efc0c15 287 }
5260325f 288 memset(passphrase, 0, strlen(passphrase));
289 xfree(passphrase);
290 RSA_free(private_key);
291
5260325f 292 strlcat(identity_file, ".pub", sizeof(identity_file));
293 f = fopen(identity_file, "w");
294 if (!f) {
295 printf("Could not save your public key in %s\n", identity_file);
296 exit(1);
297 }
298 fprintf(f, "%d ", BN_num_bits(public_key->n));
299 tmpbuf = BN_bn2dec(public_key->e);
300 fprintf(f, "%s ", tmpbuf);
301 free(tmpbuf);
302 tmpbuf = BN_bn2dec(public_key->n);
303 fprintf(f, "%s %s\n", tmpbuf, new_comment);
304 free(tmpbuf);
305 fclose(f);
306
307 xfree(comment);
308
309 printf("The comment in your key file has been changed.\n");
310 exit(0);
8efc0c15 311}
312
5ad13cd7 313void
314usage(void)
315{
5260325f 316 printf("ssh-keygen version %s\n", SSH_VERSION);
317 printf("Usage: %s [-b bits] [-p] [-c] [-f file] [-P pass] [-N new-pass] [-C comment]\n", __progname);
318 exit(1);
5ad13cd7 319}
320
5260325f 321/*
322 * Main program for key management.
323 */
8efc0c15 324int
325main(int ac, char **av)
326{
5260325f 327 char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
328 struct passwd *pw;
329 char *tmpbuf;
330 int opt;
331 struct stat st;
332 FILE *f;
333 char hostname[MAXHOSTNAMELEN];
334 extern int optind;
335 extern char *optarg;
336
337 /* check if RSA support exists */
338 if (rsa_alive() == 0) {
5260325f 339 fprintf(stderr,
340 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
341 __progname);
342 exit(1);
8efc0c15 343 }
aa3378df 344 /* we need this for the home * directory. */
5260325f 345 pw = getpwuid(getuid());
346 if (!pw) {
347 printf("You don't exist, go away!\n");
348 exit(1);
349 }
aa3378df 350
5260325f 351 while ((opt = getopt(ac, av, "qpclb:f:P:N:C:")) != EOF) {
352 switch (opt) {
353 case 'b':
354 bits = atoi(optarg);
355 if (bits < 512 || bits > 32768) {
356 printf("Bits has bad value.\n");
357 exit(1);
358 }
359 break;
360
361 case 'l':
362 print_fingerprint = 1;
363 break;
364
365 case 'p':
366 change_passphrase = 1;
367 break;
368
369 case 'c':
370 change_comment = 1;
371 break;
372
373 case 'f':
374 strlcpy(identity_file, optarg, sizeof(identity_file));
375 have_identity = 1;
376 break;
377
378 case 'P':
379 identity_passphrase = optarg;
380 break;
381
382 case 'N':
383 identity_new_passphrase = optarg;
384 break;
385
386 case 'C':
387 identity_comment = optarg;
388 break;
389
390 case 'q':
391 quiet = 1;
392 break;
393
394 case '?':
395 default:
396 usage();
397 }
398 }
399 if (optind < ac) {
400 printf("Too many arguments.\n");
401 usage();
402 }
403 if (change_passphrase && change_comment) {
404 printf("Can only have one of -p and -c.\n");
405 usage();
406 }
407 if (print_fingerprint)
408 do_fingerprint(pw);
5260325f 409 if (change_passphrase)
410 do_change_passphrase(pw);
5260325f 411 if (change_comment)
412 do_change_comment(pw);
413
414 arc4random_stir();
415
416 if (quiet)
417 rsa_set_verbose(0);
418
419 /* Generate the rsa key pair. */
420 private_key = RSA_new();
421 public_key = RSA_new();
422 rsa_generate_key(private_key, public_key, bits);
423
424 if (!have_identity)
425 ask_filename(pw, "Enter file in which to save the key");
426
427 /* Create ~/.ssh directory if it doesn\'t already exist. */
428 snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, SSH_USER_DIR);
429 if (strstr(identity_file, dotsshdir) != NULL &&
430 stat(dotsshdir, &st) < 0) {
431 if (mkdir(dotsshdir, 0755) < 0)
432 error("Could not create directory '%s'.", dotsshdir);
433 else if (!quiet)
434 printf("Created directory '%s'.\n", dotsshdir);
435 }
436 /* If the file already exists, ask the user to confirm. */
437 if (stat(identity_file, &st) >= 0) {
438 char yesno[3];
439 printf("%s already exists.\n", identity_file);
440 printf("Overwrite (y/n)? ");
441 fflush(stdout);
442 if (fgets(yesno, sizeof(yesno), stdin) == NULL)
443 exit(1);
444 if (yesno[0] != 'y' && yesno[0] != 'Y')
445 exit(1);
446 }
447 /* Ask for a passphrase (twice). */
448 if (identity_passphrase)
449 passphrase1 = xstrdup(identity_passphrase);
450 else if (identity_new_passphrase)
451 passphrase1 = xstrdup(identity_new_passphrase);
452 else {
453passphrase_again:
454 passphrase1 =
455 read_passphrase("Enter passphrase (empty for no passphrase): ", 1);
456 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
457 if (strcmp(passphrase1, passphrase2) != 0) {
458 /* The passphrases do not match. Clear them and retry. */
459 memset(passphrase1, 0, strlen(passphrase1));
460 memset(passphrase2, 0, strlen(passphrase2));
461 xfree(passphrase1);
462 xfree(passphrase2);
463 printf("Passphrases do not match. Try again.\n");
464 goto passphrase_again;
465 }
466 /* Clear the other copy of the passphrase. */
467 memset(passphrase2, 0, strlen(passphrase2));
468 xfree(passphrase2);
469 }
470
5260325f 471 if (identity_comment) {
472 strlcpy(comment, identity_comment, sizeof(comment));
473 } else {
aa3378df 474 /* Create default commend field for the passphrase. */
5260325f 475 if (gethostname(hostname, sizeof(hostname)) < 0) {
476 perror("gethostname");
477 exit(1);
478 }
479 snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
480 }
481
482 /* Save the key with the given passphrase and comment. */
483 if (!save_private_key(identity_file, passphrase1, private_key, comment)) {
484 printf("Saving the key failed: %s: %s.\n",
485 identity_file, strerror(errno));
486 memset(passphrase1, 0, strlen(passphrase1));
487 xfree(passphrase1);
488 exit(1);
489 }
490 /* Clear the passphrase. */
491 memset(passphrase1, 0, strlen(passphrase1));
492 xfree(passphrase1);
493
494 /* Clear the private key and the random number generator. */
495 RSA_free(private_key);
496 arc4random_stir();
497
498 if (!quiet)
499 printf("Your identification has been saved in %s.\n", identity_file);
500
5260325f 501 strlcat(identity_file, ".pub", sizeof(identity_file));
502 f = fopen(identity_file, "w");
503 if (!f) {
504 printf("Could not save your public key in %s\n", identity_file);
505 exit(1);
506 }
507 fprintf(f, "%d ", BN_num_bits(public_key->n));
508 tmpbuf = BN_bn2dec(public_key->e);
509 fprintf(f, "%s ", tmpbuf);
510 free(tmpbuf);
511 tmpbuf = BN_bn2dec(public_key->n);
512 fprintf(f, "%s %s\n", tmpbuf, comment);
513 free(tmpbuf);
514 fclose(f);
515
516 if (!quiet) {
517 printf("Your public key has been saved in %s.\n", identity_file);
518 printf("The key fingerprint is:\n");
519 printf("%d %s %s\n", BN_num_bits(public_key->n),
520 fingerprint(public_key->e, public_key->n),
521 comment);
8efc0c15 522 }
5260325f 523 exit(0);
8efc0c15 524}
This page took 0.144137 seconds and 5 git commands to generate.