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