2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3 * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 * Created: Mon Mar 27 02:26:40 1995 ylo
6 * Identity and host key generation and maintenance.
15 #include "fingerprint.h"
17 /* Generated private key. */
20 /* Generated public key. */
23 /* Number of bits in the RSA key. This value can be changed on the command line. */
27 * Flag indicating that we just want to change the passphrase. This can be
28 * set on the command line.
30 int change_passphrase = 0;
33 * Flag indicating that we just want to change the comment. This can be set
34 * on the command line.
36 int change_comment = 0;
40 /* Flag indicating that we just want to see the key fingerprint */
41 int print_fingerprint = 0;
43 /* The identity file name, given on the command line or entered by the user. */
44 char identity_file[1024];
45 int have_identity = 0;
47 /* This is set to the passphrase if given on the command line. */
48 char *identity_passphrase = NULL;
50 /* This is set to the new passphrase if given on the command line. */
51 char *identity_new_passphrase = NULL;
53 /* This is set to the new comment if given on the command line. */
54 char *identity_comment = NULL;
57 #ifdef HAVE___PROGNAME
58 extern char *__progname;
59 #else /* HAVE___PROGNAME */
60 const char *__progname = "ssh-keygen";
61 #endif /* HAVE___PROGNAME */
64 ask_filename(struct passwd *pw, const char *prompt)
67 snprintf(identity_file, sizeof(identity_file), "%s/%s",
68 pw->pw_dir, SSH_CLIENT_IDENTITY);
69 printf("%s (%s): ", prompt, identity_file);
71 if (fgets(buf, sizeof(buf), stdin) == NULL)
73 if (strchr(buf, '\n'))
74 *strchr(buf, '\n') = 0;
75 if (strcmp(buf, "") != 0)
76 strlcpy(identity_file, buf, sizeof(identity_file));
81 do_fingerprint(struct passwd *pw)
86 char *comment = NULL, *cp, *ep, line[16*1024];
87 int i, skip = 0, num = 1, invalid = 1;
92 ask_filename(pw, "Enter file in which the key is");
93 if (stat(identity_file, &st) < 0) {
94 perror(identity_file);
98 public_key = RSA_new();
99 if (load_public_key(identity_file, public_key, &comment)) {
100 printf("%d %s %s\n", BN_num_bits(public_key->n),
101 fingerprint(public_key->e, public_key->n),
103 RSA_free(public_key);
106 RSA_free(public_key);
108 f = fopen(identity_file, "r");
112 while (fgets(line, sizeof(line), f)) {
113 i = strlen(line) - 1;
114 if (line[i] != '\n') {
115 error("line %d too long: %.40s...", num, line);
126 /* Skip leading whitespace, empty and comment lines. */
127 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
129 if (!*cp || *cp == '\n' || *cp == '#')
131 i = strtol(cp, &ep, 10);
132 if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
135 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
136 if (*cp == '\\' && cp[1] == '"')
137 cp++; /* Skip both */
146 if (auth_rsa_read_key(&cp, &ignore, e, n)) {
148 comment = *cp ? cp : comment;
149 printf("%d %s %s\n", BN_num_bits(n),
151 comment ? comment : "no comment");
159 printf("%s is not a valid key file.\n", identity_file);
166 * Perform changing a passphrase. The argument is the passwd structure
167 * for the current user.
170 do_change_passphrase(struct passwd *pw)
173 char *old_passphrase, *passphrase1, *passphrase2;
178 ask_filename(pw, "Enter file in which the key is");
179 if (stat(identity_file, &st) < 0) {
180 perror(identity_file);
183 public_key = RSA_new();
184 if (!load_public_key(identity_file, public_key, NULL)) {
185 printf("%s is not a valid key file.\n", identity_file);
188 /* Clear the public key since we are just about to load the whole file. */
189 RSA_free(public_key);
191 /* Try to load the file with empty passphrase. */
192 private_key = RSA_new();
193 if (!load_private_key(identity_file, "", private_key, &comment)) {
194 if (identity_passphrase)
195 old_passphrase = xstrdup(identity_passphrase);
197 old_passphrase = read_passphrase("Enter old passphrase: ", 1);
198 if (!load_private_key(identity_file, old_passphrase, private_key, &comment)) {
199 memset(old_passphrase, 0, strlen(old_passphrase));
200 xfree(old_passphrase);
201 printf("Bad passphrase.\n");
204 memset(old_passphrase, 0, strlen(old_passphrase));
205 xfree(old_passphrase);
207 printf("Key has comment '%s'\n", comment);
209 /* Ask the new passphrase (twice). */
210 if (identity_new_passphrase) {
211 passphrase1 = xstrdup(identity_new_passphrase);
215 read_passphrase("Enter new passphrase (empty for no passphrase): ", 1);
216 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
218 /* Verify that they are the same. */
219 if (strcmp(passphrase1, passphrase2) != 0) {
220 memset(passphrase1, 0, strlen(passphrase1));
221 memset(passphrase2, 0, strlen(passphrase2));
224 printf("Pass phrases do not match. Try again.\n");
227 /* Destroy the other copy. */
228 memset(passphrase2, 0, strlen(passphrase2));
232 /* Save the file using the new passphrase. */
233 if (!save_private_key(identity_file, passphrase1, private_key, comment)) {
234 printf("Saving the key failed: %s: %s.\n",
235 identity_file, strerror(errno));
236 memset(passphrase1, 0, strlen(passphrase1));
238 RSA_free(private_key);
242 /* Destroy the passphrase and the copy of the key in memory. */
243 memset(passphrase1, 0, strlen(passphrase1));
245 RSA_free(private_key); /* Destroys contents */
248 printf("Your identification has been saved with the new passphrase.\n");
253 * Change the comment of a private key file.
256 do_change_comment(struct passwd *pw)
258 char new_comment[1024], *comment;
266 ask_filename(pw, "Enter file in which the key is");
267 if (stat(identity_file, &st) < 0) {
268 perror(identity_file);
272 * Try to load the public key from the file the verify that it is
273 * readable and of the proper format.
275 public_key = RSA_new();
276 if (!load_public_key(identity_file, public_key, NULL)) {
277 printf("%s is not a valid key file.\n", identity_file);
280 private_key = RSA_new();
282 if (load_private_key(identity_file, "", private_key, &comment))
283 passphrase = xstrdup("");
285 if (identity_passphrase)
286 passphrase = xstrdup(identity_passphrase);
287 else if (identity_new_passphrase)
288 passphrase = xstrdup(identity_new_passphrase);
290 passphrase = read_passphrase("Enter passphrase: ", 1);
291 /* Try to load using the passphrase. */
292 if (!load_private_key(identity_file, passphrase, private_key, &comment)) {
293 memset(passphrase, 0, strlen(passphrase));
295 printf("Bad passphrase.\n");
299 printf("Key now has comment '%s'\n", comment);
301 if (identity_comment) {
302 strlcpy(new_comment, identity_comment, sizeof(new_comment));
304 printf("Enter new comment: ");
306 if (!fgets(new_comment, sizeof(new_comment), stdin)) {
307 memset(passphrase, 0, strlen(passphrase));
308 RSA_free(private_key);
311 if (strchr(new_comment, '\n'))
312 *strchr(new_comment, '\n') = 0;
315 /* Save the file using the new passphrase. */
316 if (!save_private_key(identity_file, passphrase, private_key, new_comment)) {
317 printf("Saving the key failed: %s: %s.\n",
318 identity_file, strerror(errno));
319 memset(passphrase, 0, strlen(passphrase));
321 RSA_free(private_key);
325 memset(passphrase, 0, strlen(passphrase));
327 RSA_free(private_key);
329 strlcat(identity_file, ".pub", sizeof(identity_file));
330 f = fopen(identity_file, "w");
332 printf("Could not save your public key in %s\n", identity_file);
335 fprintf(f, "%d ", BN_num_bits(public_key->n));
336 tmpbuf = BN_bn2dec(public_key->e);
337 fprintf(f, "%s ", tmpbuf);
339 tmpbuf = BN_bn2dec(public_key->n);
340 fprintf(f, "%s %s\n", tmpbuf, new_comment);
346 printf("The comment in your key file has been changed.\n");
353 printf("ssh-keygen version %s\n", SSH_VERSION);
354 printf("Usage: %s [-b bits] [-p] [-c] [-l] [-f file] [-P pass] [-N new-pass] [-C comment]\n", __progname);
359 * Main program for key management.
362 main(int ac, char **av)
364 char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
370 char hostname[MAXHOSTNAMELEN];
374 /* check if RSA support exists */
375 if (rsa_alive() == 0) {
377 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
381 /* we need this for the home * directory. */
382 pw = getpwuid(getuid());
384 printf("You don't exist, go away!\n");
388 while ((opt = getopt(ac, av, "qpclb:f:P:N:C:")) != EOF) {
392 if (bits < 512 || bits > 32768) {
393 printf("Bits has bad value.\n");
399 print_fingerprint = 1;
403 change_passphrase = 1;
411 strlcpy(identity_file, optarg, sizeof(identity_file));
416 identity_passphrase = optarg;
420 identity_new_passphrase = optarg;
424 identity_comment = optarg;
437 printf("Too many arguments.\n");
440 if (change_passphrase && change_comment) {
441 printf("Can only have one of -p and -c.\n");
444 if (print_fingerprint)
446 if (change_passphrase)
447 do_change_passphrase(pw);
449 do_change_comment(pw);
456 /* Generate the rsa key pair. */
457 private_key = RSA_new();
458 public_key = RSA_new();
459 rsa_generate_key(private_key, public_key, bits);
462 ask_filename(pw, "Enter file in which to save the key");
464 /* Create ~/.ssh directory if it doesn\'t already exist. */
465 snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, SSH_USER_DIR);
466 if (strstr(identity_file, dotsshdir) != NULL &&
467 stat(dotsshdir, &st) < 0) {
468 if (mkdir(dotsshdir, 0755) < 0)
469 error("Could not create directory '%s'.", dotsshdir);
471 printf("Created directory '%s'.\n", dotsshdir);
473 /* If the file already exists, ask the user to confirm. */
474 if (stat(identity_file, &st) >= 0) {
476 printf("%s already exists.\n", identity_file);
477 printf("Overwrite (y/n)? ");
479 if (fgets(yesno, sizeof(yesno), stdin) == NULL)
481 if (yesno[0] != 'y' && yesno[0] != 'Y')
484 /* Ask for a passphrase (twice). */
485 if (identity_passphrase)
486 passphrase1 = xstrdup(identity_passphrase);
487 else if (identity_new_passphrase)
488 passphrase1 = xstrdup(identity_new_passphrase);
492 read_passphrase("Enter passphrase (empty for no passphrase): ", 1);
493 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
494 if (strcmp(passphrase1, passphrase2) != 0) {
495 /* The passphrases do not match. Clear them and retry. */
496 memset(passphrase1, 0, strlen(passphrase1));
497 memset(passphrase2, 0, strlen(passphrase2));
500 printf("Passphrases do not match. Try again.\n");
501 goto passphrase_again;
503 /* Clear the other copy of the passphrase. */
504 memset(passphrase2, 0, strlen(passphrase2));
508 if (identity_comment) {
509 strlcpy(comment, identity_comment, sizeof(comment));
511 /* Create default commend field for the passphrase. */
512 if (gethostname(hostname, sizeof(hostname)) < 0) {
513 perror("gethostname");
516 snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
519 /* Save the key with the given passphrase and comment. */
520 if (!save_private_key(identity_file, passphrase1, private_key, comment)) {
521 printf("Saving the key failed: %s: %s.\n",
522 identity_file, strerror(errno));
523 memset(passphrase1, 0, strlen(passphrase1));
527 /* Clear the passphrase. */
528 memset(passphrase1, 0, strlen(passphrase1));
531 /* Clear the private key and the random number generator. */
532 RSA_free(private_key);
536 printf("Your identification has been saved in %s.\n", identity_file);
538 strlcat(identity_file, ".pub", sizeof(identity_file));
539 f = fopen(identity_file, "w");
541 printf("Could not save your public key in %s\n", identity_file);
544 fprintf(f, "%d ", BN_num_bits(public_key->n));
545 tmpbuf = BN_bn2dec(public_key->e);
546 fprintf(f, "%s ", tmpbuf);
548 tmpbuf = BN_bn2dec(public_key->n);
549 fprintf(f, "%s %s\n", tmpbuf, comment);
554 printf("Your public key has been saved in %s.\n", identity_file);
555 printf("The key fingerprint is:\n");
556 printf("%d %s %s\n", BN_num_bits(public_key->n),
557 fingerprint(public_key->e, public_key->n),