]> andersk Git - openssh.git/blame - ssh-keygen.c
- OpenBSD CVS Sync
[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
5260325f 5 * Identity and host key generation and maintenance.
bcbf86ec 6 *
7 * As far as I am concerned, the code I have written for this software
8 * can be used freely for any purpose. Any derived versions of this
9 * software must be clearly marked as such, and if the derived work is
10 * incompatible with the protocol description in the RFC file, it must be
11 * called by a name other than "ssh" or "Secure Shell".
5260325f 12 */
8efc0c15 13
14#include "includes.h"
22138a36 15RCSID("$OpenBSD: ssh-keygen.c,v 1.50 2001/03/12 22:02:02 markus Exp $");
8efc0c15 16
a306f2dd 17#include <openssl/evp.h>
18#include <openssl/pem.h>
a306f2dd 19
8efc0c15 20#include "xmalloc.h"
a306f2dd 21#include "key.h"
a306f2dd 22#include "authfile.h"
23#include "uuencode.h"
94ec8c6b 24#include "buffer.h"
25#include "bufaux.h"
42f11eb2 26#include "pathnames.h"
27#include "log.h"
28#include "readpass.h"
94ec8c6b 29
a306f2dd 30/* Number of bits in the RSA/DSA key. This value can be changed on the command line. */
8efc0c15 31int bits = 1024;
32
aa3378df 33/*
34 * Flag indicating that we just want to change the passphrase. This can be
35 * set on the command line.
36 */
8efc0c15 37int change_passphrase = 0;
38
aa3378df 39/*
40 * Flag indicating that we just want to change the comment. This can be set
41 * on the command line.
42 */
8efc0c15 43int change_comment = 0;
44
45int quiet = 0;
46
f095fcc7 47/* Flag indicating that we just want to see the key fingerprint */
48int print_fingerprint = 0;
aaf45d87 49int print_bubblebabble = 0;
f095fcc7 50
5ad13cd7 51/* The identity file name, given on the command line or entered by the user. */
52char identity_file[1024];
53int have_identity = 0;
8efc0c15 54
55/* This is set to the passphrase if given on the command line. */
56char *identity_passphrase = NULL;
57
58/* This is set to the new passphrase if given on the command line. */
59char *identity_new_passphrase = NULL;
60
61/* This is set to the new comment if given on the command line. */
62char *identity_comment = NULL;
63
a306f2dd 64/* Dump public key file in format used by real and the original SSH 2 */
65int convert_to_ssh2 = 0;
66int convert_from_ssh2 = 0;
67int print_public = 0;
fa08c86b 68
c523303b 69/* default to RSA for SSH-1 */
70char *key_type_name = "rsa1";
a306f2dd 71
5ad13cd7 72/* argv0 */
5260325f 73#ifdef HAVE___PROGNAME
5ad13cd7 74extern char *__progname;
260d427b 75#else
76char *__progname;
77#endif
8efc0c15 78
a306f2dd 79char hostname[MAXHOSTNAMELEN];
80
5ad13cd7 81void
82ask_filename(struct passwd *pw, const char *prompt)
8efc0c15 83{
5260325f 84 char buf[1024];
c523303b 85 char *name = NULL;
86
87 switch (key_type_from_name(key_type_name)) {
88 case KEY_RSA1:
42f11eb2 89 name = _PATH_SSH_CLIENT_IDENTITY;
c523303b 90 break;
91 case KEY_DSA:
42f11eb2 92 name = _PATH_SSH_CLIENT_ID_DSA;
c523303b 93 break;
94 case KEY_RSA:
42f11eb2 95 name = _PATH_SSH_CLIENT_ID_RSA;
c523303b 96 break;
97 default:
98 fprintf(stderr, "bad key type");
99 exit(1);
100 break;
101 }
102 snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name);
8d88011e 103 fprintf(stderr, "%s (%s): ", prompt, identity_file);
104 fflush(stderr);
5260325f 105 if (fgets(buf, sizeof(buf), stdin) == NULL)
106 exit(1);
107 if (strchr(buf, '\n'))
108 *strchr(buf, '\n') = 0;
109 if (strcmp(buf, "") != 0)
110 strlcpy(identity_file, buf, sizeof(identity_file));
111 have_identity = 1;
f095fcc7 112}
8efc0c15 113
a306f2dd 114int
115try_load_key(char *filename, Key *k)
116{
117 int success = 1;
118 if (!load_private_key(filename, "", k, NULL)) {
119 char *pass = read_passphrase("Enter passphrase: ", 1);
120 if (!load_private_key(filename, pass, k, NULL)) {
121 success = 0;
122 }
123 memset(pass, 0, strlen(pass));
124 xfree(pass);
125 }
126 return success;
127}
128
94ec8c6b 129#define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
130#define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----"
131#define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
2b87da3b 132#define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb
a306f2dd 133
134void
135do_convert_to_ssh2(struct passwd *pw)
136{
137 Key *k;
138 int len;
1e3b8b07 139 u_char *blob;
a306f2dd 140 struct stat st;
141
142 if (!have_identity)
143 ask_filename(pw, "Enter file in which the key is");
144 if (stat(identity_file, &st) < 0) {
145 perror(identity_file);
146 exit(1);
147 }
fa08c86b 148 k = key_new(KEY_UNSPEC);
a306f2dd 149 if (!try_load_key(identity_file, k)) {
150 fprintf(stderr, "load failed\n");
151 exit(1);
152 }
fa08c86b 153 key_to_blob(k, &blob, &len);
94ec8c6b 154 fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
a306f2dd 155 fprintf(stdout,
94ec8c6b 156 "Comment: \"%d-bit %s, converted from OpenSSH by %s@%s\"\n",
157 key_size(k), key_type(k),
a306f2dd 158 pw->pw_name, hostname);
159 dump_base64(stdout, blob, len);
94ec8c6b 160 fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
a306f2dd 161 key_free(k);
162 xfree(blob);
163 exit(0);
164}
165
94ec8c6b 166void
167buffer_get_bignum_bits(Buffer *b, BIGNUM *value)
168{
169 int bits = buffer_get_int(b);
170 int bytes = (bits + 7) / 8;
171 if (buffer_len(b) < bytes)
172 fatal("buffer_get_bignum_bits: input buffer too small");
1e3b8b07 173 BN_bin2bn((u_char *)buffer_ptr(b), bytes, value);
94ec8c6b 174 buffer_consume(b, bytes);
175}
176
177Key *
178do_convert_private_ssh2_from_blob(char *blob, int blen)
179{
180 Buffer b;
181 DSA *dsa;
182 Key *key = NULL;
183 int ignore, magic, rlen;
184 char *type, *cipher;
185
186 buffer_init(&b);
187 buffer_append(&b, blob, blen);
188
189 magic = buffer_get_int(&b);
190 if (magic != SSH_COM_PRIVATE_KEY_MAGIC) {
191 error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC);
192 buffer_free(&b);
193 return NULL;
194 }
195 ignore = buffer_get_int(&b);
196 type = buffer_get_string(&b, NULL);
197 cipher = buffer_get_string(&b, NULL);
198 ignore = buffer_get_int(&b);
199 ignore = buffer_get_int(&b);
200 ignore = buffer_get_int(&b);
201 xfree(type);
202
203 if (strcmp(cipher, "none") != 0) {
204 error("unsupported cipher %s", cipher);
205 xfree(cipher);
206 buffer_free(&b);
207 return NULL;
208 }
209 xfree(cipher);
210
211 key = key_new(KEY_DSA);
212 dsa = key->dsa;
213 dsa->priv_key = BN_new();
214 if (dsa->priv_key == NULL) {
215 error("alloc priv_key failed");
216 key_free(key);
217 return NULL;
218 }
219 buffer_get_bignum_bits(&b, dsa->p);
220 buffer_get_bignum_bits(&b, dsa->g);
221 buffer_get_bignum_bits(&b, dsa->q);
222 buffer_get_bignum_bits(&b, dsa->pub_key);
223 buffer_get_bignum_bits(&b, dsa->priv_key);
224 rlen = buffer_len(&b);
225 if(rlen != 0)
226 error("do_convert_private_ssh2_from_blob: remaining bytes in key blob %d", rlen);
227 buffer_free(&b);
228 return key;
229}
230
a306f2dd 231void
232do_convert_from_ssh2(struct passwd *pw)
233{
234 Key *k;
235 int blen;
236 char line[1024], *p;
237 char blob[8096];
238 char encoded[8096];
239 struct stat st;
94ec8c6b 240 int escaped = 0, private = 0, ok;
a306f2dd 241 FILE *fp;
242
243 if (!have_identity)
244 ask_filename(pw, "Enter file in which the key is");
245 if (stat(identity_file, &st) < 0) {
246 perror(identity_file);
247 exit(1);
248 }
249 fp = fopen(identity_file, "r");
250 if (fp == NULL) {
251 perror(identity_file);
252 exit(1);
253 }
254 encoded[0] = '\0';
255 while (fgets(line, sizeof(line), fp)) {
d0c832f3 256 if (!(p = strchr(line, '\n'))) {
257 fprintf(stderr, "input line too long.\n");
258 exit(1);
259 }
260 if (p > line && p[-1] == '\\')
261 escaped++;
a306f2dd 262 if (strncmp(line, "----", 4) == 0 ||
263 strstr(line, ": ") != NULL) {
94ec8c6b 264 if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL)
265 private = 1;
a306f2dd 266 fprintf(stderr, "ignore: %s", line);
267 continue;
268 }
d0c832f3 269 if (escaped) {
270 escaped--;
271 fprintf(stderr, "escaped: %s", line);
272 continue;
a306f2dd 273 }
274 *p = '\0';
275 strlcat(encoded, line, sizeof(encoded));
276 }
1e3b8b07 277 blen = uudecode(encoded, (u_char *)blob, sizeof(blob));
a306f2dd 278 if (blen < 0) {
279 fprintf(stderr, "uudecode failed.\n");
280 exit(1);
281 }
94ec8c6b 282 k = private ?
283 do_convert_private_ssh2_from_blob(blob, blen) :
fa08c86b 284 key_from_blob(blob, blen);
94ec8c6b 285 if (k == NULL) {
286 fprintf(stderr, "decode blob failed.\n");
287 exit(1);
288 }
289 ok = private ?
290 PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) :
291 key_write(k, stdout);
292 if (!ok) {
293 fprintf(stderr, "key write failed");
294 exit(1);
295 }
a306f2dd 296 key_free(k);
297 fprintf(stdout, "\n");
298 fclose(fp);
299 exit(0);
300}
301
302void
303do_print_public(struct passwd *pw)
304{
305 Key *k;
a306f2dd 306 struct stat st;
307
308 if (!have_identity)
309 ask_filename(pw, "Enter file in which the key is");
310 if (stat(identity_file, &st) < 0) {
311 perror(identity_file);
312 exit(1);
313 }
fa08c86b 314 k = key_new(KEY_UNSPEC);
a306f2dd 315 if (!try_load_key(identity_file, k)) {
316 fprintf(stderr, "load failed\n");
317 exit(1);
318 }
a306f2dd 319 if (!key_write(k, stdout))
320 fprintf(stderr, "key_write failed");
321 key_free(k);
a306f2dd 322 fprintf(stdout, "\n");
323 exit(0);
324}
325
f095fcc7 326void
327do_fingerprint(struct passwd *pw)
328{
c8d54615 329 FILE *f;
a306f2dd 330 Key *public;
aaf45d87 331 char *comment = NULL, *cp, *ep, line[16*1024], *fp;
332 int i, skip = 0, num = 1, invalid = 1, success = 0, rep, type;
5260325f 333 struct stat st;
334
aaf45d87 335 type = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
336 rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
337
5260325f 338 if (!have_identity)
339 ask_filename(pw, "Enter file in which the key is");
340 if (stat(identity_file, &st) < 0) {
341 perror(identity_file);
342 exit(1);
343 }
fa08c86b 344 public = key_new(KEY_RSA1);
a306f2dd 345 if (load_public_key(identity_file, public, &comment)) {
fa08c86b 346 success = 1;
347 } else {
348 key_free(public);
349 public = key_new(KEY_UNSPEC);
350 if (try_load_public_key(identity_file, public, &comment))
351 success = 1;
352 else
efcae5b1 353 debug("try_load_public_key KEY_UNSPEC failed");
fa08c86b 354 }
355 if (success) {
22138a36 356 fp = key_fingerprint(public, type, rep);
aaf45d87 357 printf("%d %s %s\n", key_size(public),
358 fp, comment);
a306f2dd 359 key_free(public);
fa08c86b 360 xfree(comment);
aaf45d87 361 xfree(fp);
c8d54615 362 exit(0);
363 }
c8d54615 364
365 f = fopen(identity_file, "r");
366 if (f != NULL) {
c8d54615 367 while (fgets(line, sizeof(line), f)) {
368 i = strlen(line) - 1;
369 if (line[i] != '\n') {
370 error("line %d too long: %.40s...", num, line);
371 skip = 1;
372 continue;
373 }
374 num++;
375 if (skip) {
376 skip = 0;
377 continue;
378 }
379 line[i] = '\0';
380
381 /* Skip leading whitespace, empty and comment lines. */
382 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
383 ;
384 if (!*cp || *cp == '\n' || *cp == '#')
385 continue ;
386 i = strtol(cp, &ep, 10);
387 if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
388 int quoted = 0;
389 comment = cp;
390 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
391 if (*cp == '\\' && cp[1] == '"')
392 cp++; /* Skip both */
393 else if (*cp == '"')
394 quoted = !quoted;
395 }
396 if (!*cp)
397 continue;
398 *cp++ = '\0';
399 }
400 ep = cp;
efcae5b1 401 public = key_new(KEY_RSA1);
402 if (key_read(public, &cp) != 1) {
403 cp = ep;
404 key_free(public);
405 public = key_new(KEY_UNSPEC);
406 if (key_read(public, &cp) != 1) {
407 key_free(public);
408 continue;
409 }
5260325f 410 }
efcae5b1 411 comment = *cp ? cp : comment;
22138a36 412 fp = key_fingerprint(public, type, rep);
aaf45d87 413 printf("%d %s %s\n", key_size(public), fp,
efcae5b1 414 comment ? comment : "no comment");
aaf45d87 415 xfree(fp);
efcae5b1 416 invalid = 0;
5260325f 417 }
c8d54615 418 fclose(f);
419 }
2e73a022 420 key_free(public);
c8d54615 421 if (invalid) {
422 printf("%s is not a valid key file.\n", identity_file);
423 exit(1);
5260325f 424 }
5260325f 425 exit(0);
f095fcc7 426}
427
5260325f 428/*
429 * Perform changing a passphrase. The argument is the passwd structure
430 * for the current user.
431 */
f095fcc7 432void
433do_change_passphrase(struct passwd *pw)
434{
5260325f 435 char *comment;
436 char *old_passphrase, *passphrase1, *passphrase2;
437 struct stat st;
a306f2dd 438 Key *private;
439 Key *public;
fa08c86b 440 int type = KEY_RSA1;
5260325f 441
442 if (!have_identity)
443 ask_filename(pw, "Enter file in which the key is");
5260325f 444 if (stat(identity_file, &st) < 0) {
445 perror(identity_file);
446 exit(1);
447 }
fa08c86b 448 public = key_new(type);
449 if (!load_public_key(identity_file, public, NULL)) {
450 type = KEY_UNSPEC;
451 } else {
a306f2dd 452 /* Clear the public key since we are just about to load the whole file. */
453 key_free(public);
5260325f 454 }
5260325f 455 /* Try to load the file with empty passphrase. */
a306f2dd 456 private = key_new(type);
457 if (!load_private_key(identity_file, "", private, &comment)) {
5260325f 458 if (identity_passphrase)
459 old_passphrase = xstrdup(identity_passphrase);
460 else
461 old_passphrase = read_passphrase("Enter old passphrase: ", 1);
a306f2dd 462 if (!load_private_key(identity_file, old_passphrase, private, &comment)) {
5260325f 463 memset(old_passphrase, 0, strlen(old_passphrase));
464 xfree(old_passphrase);
465 printf("Bad passphrase.\n");
466 exit(1);
467 }
5260325f 468 memset(old_passphrase, 0, strlen(old_passphrase));
469 xfree(old_passphrase);
470 }
471 printf("Key has comment '%s'\n", comment);
472
473 /* Ask the new passphrase (twice). */
474 if (identity_new_passphrase) {
475 passphrase1 = xstrdup(identity_new_passphrase);
476 passphrase2 = NULL;
477 } else {
478 passphrase1 =
479 read_passphrase("Enter new passphrase (empty for no passphrase): ", 1);
480 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
481
482 /* Verify that they are the same. */
483 if (strcmp(passphrase1, passphrase2) != 0) {
484 memset(passphrase1, 0, strlen(passphrase1));
485 memset(passphrase2, 0, strlen(passphrase2));
486 xfree(passphrase1);
487 xfree(passphrase2);
488 printf("Pass phrases do not match. Try again.\n");
489 exit(1);
490 }
491 /* Destroy the other copy. */
492 memset(passphrase2, 0, strlen(passphrase2));
493 xfree(passphrase2);
8efc0c15 494 }
8efc0c15 495
5260325f 496 /* Save the file using the new passphrase. */
a306f2dd 497 if (!save_private_key(identity_file, passphrase1, private, comment)) {
5260325f 498 printf("Saving the key failed: %s: %s.\n",
499 identity_file, strerror(errno));
500 memset(passphrase1, 0, strlen(passphrase1));
501 xfree(passphrase1);
a306f2dd 502 key_free(private);
5260325f 503 xfree(comment);
504 exit(1);
505 }
506 /* Destroy the passphrase and the copy of the key in memory. */
507 memset(passphrase1, 0, strlen(passphrase1));
508 xfree(passphrase1);
a306f2dd 509 key_free(private); /* Destroys contents */
5260325f 510 xfree(comment);
511
512 printf("Your identification has been saved with the new passphrase.\n");
513 exit(0);
514}
8efc0c15 515
5260325f 516/*
517 * Change the comment of a private key file.
518 */
8efc0c15 519void
520do_change_comment(struct passwd *pw)
521{
1c9a907f 522 char new_comment[1024], *comment, *passphrase;
523 Key *private, *public;
5260325f 524 struct stat st;
525 FILE *f;
1c9a907f 526 int fd;
5260325f 527
528 if (!have_identity)
529 ask_filename(pw, "Enter file in which the key is");
5260325f 530 if (stat(identity_file, &st) < 0) {
531 perror(identity_file);
532 exit(1);
533 }
aa3378df 534 /*
535 * Try to load the public key from the file the verify that it is
536 * readable and of the proper format.
537 */
fa08c86b 538 public = key_new(KEY_RSA1);
a306f2dd 539 if (!load_public_key(identity_file, public, NULL)) {
5260325f 540 printf("%s is not a valid key file.\n", identity_file);
15853e93 541 printf("Comments are only supported in RSA1 keys\n");
5260325f 542 exit(1);
8efc0c15 543 }
aa3378df 544
fa08c86b 545 private = key_new(KEY_RSA1);
a306f2dd 546 if (load_private_key(identity_file, "", private, &comment))
5260325f 547 passphrase = xstrdup("");
548 else {
5260325f 549 if (identity_passphrase)
550 passphrase = xstrdup(identity_passphrase);
551 else if (identity_new_passphrase)
552 passphrase = xstrdup(identity_new_passphrase);
553 else
554 passphrase = read_passphrase("Enter passphrase: ", 1);
555 /* Try to load using the passphrase. */
a306f2dd 556 if (!load_private_key(identity_file, passphrase, private, &comment)) {
5260325f 557 memset(passphrase, 0, strlen(passphrase));
558 xfree(passphrase);
559 printf("Bad passphrase.\n");
560 exit(1);
561 }
562 }
563 printf("Key now has comment '%s'\n", comment);
564
565 if (identity_comment) {
566 strlcpy(new_comment, identity_comment, sizeof(new_comment));
567 } else {
568 printf("Enter new comment: ");
569 fflush(stdout);
570 if (!fgets(new_comment, sizeof(new_comment), stdin)) {
571 memset(passphrase, 0, strlen(passphrase));
a306f2dd 572 key_free(private);
5260325f 573 exit(1);
574 }
5260325f 575 if (strchr(new_comment, '\n'))
576 *strchr(new_comment, '\n') = 0;
577 }
578
579 /* Save the file using the new passphrase. */
a306f2dd 580 if (!save_private_key(identity_file, passphrase, private, new_comment)) {
5260325f 581 printf("Saving the key failed: %s: %s.\n",
582 identity_file, strerror(errno));
583 memset(passphrase, 0, strlen(passphrase));
584 xfree(passphrase);
a306f2dd 585 key_free(private);
5260325f 586 xfree(comment);
587 exit(1);
8efc0c15 588 }
5260325f 589 memset(passphrase, 0, strlen(passphrase));
590 xfree(passphrase);
a306f2dd 591 key_free(private);
5260325f 592
5260325f 593 strlcat(identity_file, ".pub", sizeof(identity_file));
1c9a907f 594 fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
595 if (fd == -1) {
5260325f 596 printf("Could not save your public key in %s\n", identity_file);
597 exit(1);
598 }
1c9a907f 599 f = fdopen(fd, "w");
600 if (f == NULL) {
601 printf("fdopen %s failed", identity_file);
602 exit(1);
603 }
a306f2dd 604 if (!key_write(public, f))
605 fprintf(stderr, "write key failed");
606 key_free(public);
607 fprintf(f, " %s\n", new_comment);
5260325f 608 fclose(f);
609
610 xfree(comment);
611
612 printf("The comment in your key file has been changed.\n");
613 exit(0);
8efc0c15 614}
615
5ad13cd7 616void
617usage(void)
618{
b07ae1e9 619 printf("Usage: %s [-lpqxXyc] [-t type] [-b bits] [-f file] [-C comment] "
ed2166d8 620 "[-N new-pass] [-P pass]\n", __progname);
5260325f 621 exit(1);
5ad13cd7 622}
623
5260325f 624/*
625 * Main program for key management.
626 */
8efc0c15 627int
628main(int ac, char **av)
629{
5260325f 630 char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
1c9a907f 631 Key *private, *public;
5260325f 632 struct passwd *pw;
1c9a907f 633 int opt, type, fd;
5260325f 634 struct stat st;
635 FILE *f;
fa08c86b 636
5260325f 637 extern int optind;
638 extern char *optarg;
639
260d427b 640 __progname = get_progname(av[0]);
264dce47 641 init_rng();
642
fa649821 643 SSLeay_add_all_algorithms();
a306f2dd 644
aa3378df 645 /* we need this for the home * directory. */
5260325f 646 pw = getpwuid(getuid());
647 if (!pw) {
648 printf("You don't exist, go away!\n");
649 exit(1);
650 }
a306f2dd 651 if (gethostname(hostname, sizeof(hostname)) < 0) {
652 perror("gethostname");
653 exit(1);
654 }
aa3378df 655
aaf45d87 656 while ((opt = getopt(ac, av, "dqpclBRxXyb:f:t:P:N:C:")) != -1) {
5260325f 657 switch (opt) {
658 case 'b':
659 bits = atoi(optarg);
660 if (bits < 512 || bits > 32768) {
661 printf("Bits has bad value.\n");
662 exit(1);
663 }
664 break;
665
666 case 'l':
667 print_fingerprint = 1;
668 break;
669
aaf45d87 670 case 'B':
671 print_bubblebabble = 1;
672 break;
673
5260325f 674 case 'p':
675 change_passphrase = 1;
676 break;
677
678 case 'c':
679 change_comment = 1;
680 break;
681
682 case 'f':
683 strlcpy(identity_file, optarg, sizeof(identity_file));
684 have_identity = 1;
685 break;
686
687 case 'P':
688 identity_passphrase = optarg;
689 break;
690
691 case 'N':
692 identity_new_passphrase = optarg;
693 break;
694
695 case 'C':
696 identity_comment = optarg;
697 break;
698
699 case 'q':
700 quiet = 1;
701 break;
702
a306f2dd 703 case 'R':
fa08c86b 704 /* unused */
705 exit(0);
a306f2dd 706 break;
707
708 case 'x':
709 convert_to_ssh2 = 1;
710 break;
711
712 case 'X':
713 convert_from_ssh2 = 1;
714 break;
715
716 case 'y':
717 print_public = 1;
718 break;
954f0550 719
a306f2dd 720 case 'd':
fa08c86b 721 key_type_name = "dsa";
a306f2dd 722 break;
723
fa08c86b 724 case 't':
725 key_type_name = optarg;
fa08c86b 726 break;
727
5260325f 728 case '?':
729 default:
730 usage();
731 }
732 }
733 if (optind < ac) {
734 printf("Too many arguments.\n");
735 usage();
736 }
737 if (change_passphrase && change_comment) {
738 printf("Can only have one of -p and -c.\n");
739 usage();
740 }
aaf45d87 741 if (print_fingerprint || print_bubblebabble)
5260325f 742 do_fingerprint(pw);
5260325f 743 if (change_passphrase)
744 do_change_passphrase(pw);
5260325f 745 if (change_comment)
746 do_change_comment(pw);
a306f2dd 747 if (convert_to_ssh2)
748 do_convert_to_ssh2(pw);
749 if (convert_from_ssh2)
750 do_convert_from_ssh2(pw);
751 if (print_public)
752 do_print_public(pw);
5260325f 753
754 arc4random_stir();
755
c523303b 756 type = key_type_from_name(key_type_name);
757 if (type == KEY_UNSPEC) {
758 fprintf(stderr, "unknown key type %s\n", key_type_name);
759 exit(1);
a306f2dd 760 }
fa08c86b 761 if (!quiet)
c523303b 762 printf("Generating public/private %s key pair.\n", key_type_name);
fa08c86b 763 private = key_generate(type, bits);
764 if (private == NULL) {
765 fprintf(stderr, "key_generate failed");
766 exit(1);
767 }
768 public = key_from_private(private);
5260325f 769
770 if (!have_identity)
771 ask_filename(pw, "Enter file in which to save the key");
772
773 /* Create ~/.ssh directory if it doesn\'t already exist. */
42f11eb2 774 snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR);
5260325f 775 if (strstr(identity_file, dotsshdir) != NULL &&
776 stat(dotsshdir, &st) < 0) {
704b1659 777 if (mkdir(dotsshdir, 0700) < 0)
5260325f 778 error("Could not create directory '%s'.", dotsshdir);
779 else if (!quiet)
780 printf("Created directory '%s'.\n", dotsshdir);
781 }
782 /* If the file already exists, ask the user to confirm. */
783 if (stat(identity_file, &st) >= 0) {
784 char yesno[3];
785 printf("%s already exists.\n", identity_file);
786 printf("Overwrite (y/n)? ");
787 fflush(stdout);
788 if (fgets(yesno, sizeof(yesno), stdin) == NULL)
789 exit(1);
790 if (yesno[0] != 'y' && yesno[0] != 'Y')
791 exit(1);
792 }
793 /* Ask for a passphrase (twice). */
794 if (identity_passphrase)
795 passphrase1 = xstrdup(identity_passphrase);
796 else if (identity_new_passphrase)
797 passphrase1 = xstrdup(identity_new_passphrase);
798 else {
799passphrase_again:
800 passphrase1 =
801 read_passphrase("Enter passphrase (empty for no passphrase): ", 1);
802 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
803 if (strcmp(passphrase1, passphrase2) != 0) {
804 /* The passphrases do not match. Clear them and retry. */
805 memset(passphrase1, 0, strlen(passphrase1));
806 memset(passphrase2, 0, strlen(passphrase2));
807 xfree(passphrase1);
808 xfree(passphrase2);
809 printf("Passphrases do not match. Try again.\n");
810 goto passphrase_again;
811 }
812 /* Clear the other copy of the passphrase. */
813 memset(passphrase2, 0, strlen(passphrase2));
814 xfree(passphrase2);
815 }
816
5260325f 817 if (identity_comment) {
818 strlcpy(comment, identity_comment, sizeof(comment));
819 } else {
6ae2364d 820 /* Create default commend field for the passphrase. */
5260325f 821 snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
822 }
823
824 /* Save the key with the given passphrase and comment. */
a306f2dd 825 if (!save_private_key(identity_file, passphrase1, private, comment)) {
5260325f 826 printf("Saving the key failed: %s: %s.\n",
a306f2dd 827 identity_file, strerror(errno));
5260325f 828 memset(passphrase1, 0, strlen(passphrase1));
829 xfree(passphrase1);
830 exit(1);
831 }
832 /* Clear the passphrase. */
833 memset(passphrase1, 0, strlen(passphrase1));
834 xfree(passphrase1);
835
836 /* Clear the private key and the random number generator. */
fa08c86b 837 key_free(private);
5260325f 838 arc4random_stir();
839
840 if (!quiet)
841 printf("Your identification has been saved in %s.\n", identity_file);
842
5260325f 843 strlcat(identity_file, ".pub", sizeof(identity_file));
1c9a907f 844 fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
845 if (fd == -1) {
5260325f 846 printf("Could not save your public key in %s\n", identity_file);
847 exit(1);
848 }
1c9a907f 849 f = fdopen(fd, "w");
850 if (f == NULL) {
851 printf("fdopen %s failed", identity_file);
852 exit(1);
853 }
a306f2dd 854 if (!key_write(public, f))
855 fprintf(stderr, "write key failed");
856 fprintf(f, " %s\n", comment);
5260325f 857 fclose(f);
858
859 if (!quiet) {
22138a36 860 char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
a306f2dd 861 printf("Your public key has been saved in %s.\n",
862 identity_file);
5260325f 863 printf("The key fingerprint is:\n");
22138a36 864 printf("%s %s\n", fp, comment);
865 xfree(fp);
8efc0c15 866 }
a306f2dd 867
868 key_free(public);
5260325f 869 exit(0);
8efc0c15 870}
This page took 0.294386 seconds and 5 git commands to generate.