blob: 51b0034057367d3aba88a2ec96c8d05213a45daf [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
Damien Miller95def091999-11-25 00:26:21 +11005 * Identity and host key generation and maintenance.
Damien Millere4340be2000-09-16 13:29:08 +11006 *
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".
Damien Miller95def091999-11-25 00:26:21 +110012 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100013
14#include "includes.h"
Ben Lindstrome586c4c2001-06-25 05:04:58 +000015RCSID("$OpenBSD: ssh-keygen.c,v 1.64 2001/06/23 17:05:22 markus Exp $");
Damien Millerd4a8b7e1999-10-27 13:42:43 +100016
Damien Millereba71ba2000-04-29 23:57:08 +100017#include <openssl/evp.h>
18#include <openssl/pem.h>
Damien Millereba71ba2000-04-29 23:57:08 +100019
Damien Millerd4a8b7e1999-10-27 13:42:43 +100020#include "xmalloc.h"
Damien Millereba71ba2000-04-29 23:57:08 +100021#include "key.h"
Ben Lindstromd09fcf52001-03-29 00:29:54 +000022#include "rsa.h"
Damien Millereba71ba2000-04-29 23:57:08 +100023#include "authfile.h"
24#include "uuencode.h"
Damien Miller874d77b2000-10-14 16:23:11 +110025#include "buffer.h"
26#include "bufaux.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000027#include "pathnames.h"
28#include "log.h"
29#include "readpass.h"
Damien Miller874d77b2000-10-14 16:23:11 +110030
Damien Millereba71ba2000-04-29 23:57:08 +100031/* Number of bits in the RSA/DSA key. This value can be changed on the command line. */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100032int bits = 1024;
33
Damien Miller5428f641999-11-25 11:54:57 +110034/*
35 * Flag indicating that we just want to change the passphrase. This can be
36 * set on the command line.
37 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100038int change_passphrase = 0;
39
Damien Miller5428f641999-11-25 11:54:57 +110040/*
41 * Flag indicating that we just want to change the comment. This can be set
42 * on the command line.
43 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100044int change_comment = 0;
45
46int quiet = 0;
47
Damien Miller10f6f6b1999-11-17 17:29:08 +110048/* Flag indicating that we just want to see the key fingerprint */
49int print_fingerprint = 0;
Ben Lindstrom8fd372b2001-03-12 03:02:17 +000050int print_bubblebabble = 0;
Damien Miller10f6f6b1999-11-17 17:29:08 +110051
Damien Miller431f66b1999-11-21 18:31:57 +110052/* The identity file name, given on the command line or entered by the user. */
53char identity_file[1024];
54int have_identity = 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100055
56/* This is set to the passphrase if given on the command line. */
57char *identity_passphrase = NULL;
58
59/* This is set to the new passphrase if given on the command line. */
60char *identity_new_passphrase = NULL;
61
62/* This is set to the new comment if given on the command line. */
63char *identity_comment = NULL;
64
Damien Millereba71ba2000-04-29 23:57:08 +100065/* Dump public key file in format used by real and the original SSH 2 */
66int convert_to_ssh2 = 0;
67int convert_from_ssh2 = 0;
68int print_public = 0;
Damien Miller0bc1bd82000-11-13 22:57:25 +110069
Damien Millere39cacc2000-11-29 12:18:44 +110070/* default to RSA for SSH-1 */
71char *key_type_name = "rsa1";
Damien Millereba71ba2000-04-29 23:57:08 +100072
Damien Miller431f66b1999-11-21 18:31:57 +110073/* argv0 */
Damien Miller95def091999-11-25 00:26:21 +110074#ifdef HAVE___PROGNAME
Damien Miller431f66b1999-11-21 18:31:57 +110075extern char *__progname;
Ben Lindstrom49a79c02000-11-17 03:47:20 +000076#else
77char *__progname;
78#endif
Damien Millerd4a8b7e1999-10-27 13:42:43 +100079
Damien Millereba71ba2000-04-29 23:57:08 +100080char hostname[MAXHOSTNAMELEN];
81
Ben Lindstrombba81212001-06-25 05:01:22 +000082static void
Damien Miller431f66b1999-11-21 18:31:57 +110083ask_filename(struct passwd *pw, const char *prompt)
Damien Millerd4a8b7e1999-10-27 13:42:43 +100084{
Damien Miller95def091999-11-25 00:26:21 +110085 char buf[1024];
Damien Millere39cacc2000-11-29 12:18:44 +110086 char *name = NULL;
87
88 switch (key_type_from_name(key_type_name)) {
89 case KEY_RSA1:
Ben Lindstrom226cfa02001-01-22 05:34:40 +000090 name = _PATH_SSH_CLIENT_IDENTITY;
Damien Millere39cacc2000-11-29 12:18:44 +110091 break;
92 case KEY_DSA:
Ben Lindstrom226cfa02001-01-22 05:34:40 +000093 name = _PATH_SSH_CLIENT_ID_DSA;
Damien Millere39cacc2000-11-29 12:18:44 +110094 break;
95 case KEY_RSA:
Ben Lindstrom226cfa02001-01-22 05:34:40 +000096 name = _PATH_SSH_CLIENT_ID_RSA;
Damien Millere39cacc2000-11-29 12:18:44 +110097 break;
98 default:
99 fprintf(stderr, "bad key type");
100 exit(1);
101 break;
102 }
103 snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name);
Ben Lindstrom3deda8b2000-12-22 20:27:43 +0000104 fprintf(stderr, "%s (%s): ", prompt, identity_file);
105 fflush(stderr);
Damien Miller95def091999-11-25 00:26:21 +1100106 if (fgets(buf, sizeof(buf), stdin) == NULL)
107 exit(1);
108 if (strchr(buf, '\n'))
109 *strchr(buf, '\n') = 0;
110 if (strcmp(buf, "") != 0)
111 strlcpy(identity_file, buf, sizeof(identity_file));
112 have_identity = 1;
Damien Miller10f6f6b1999-11-17 17:29:08 +1100113}
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000114
Ben Lindstrombba81212001-06-25 05:01:22 +0000115static Key *
Ben Lindstromd78ae762001-06-05 20:35:09 +0000116load_identity(char *filename)
Damien Millereba71ba2000-04-29 23:57:08 +1000117{
Ben Lindstromd0fca422001-03-26 13:44:06 +0000118 char *pass;
119 Key *prv;
120
Ben Lindstroma3700052001-04-05 23:26:32 +0000121 prv = key_load_private(filename, "", NULL);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000122 if (prv == NULL) {
Ben Lindstromd78ae762001-06-05 20:35:09 +0000123 if (identity_passphrase)
124 pass = xstrdup(identity_passphrase);
125 else
126 pass = read_passphrase("Enter passphrase: ", 1);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000127 prv = key_load_private(filename, pass, NULL);
Damien Millereba71ba2000-04-29 23:57:08 +1000128 memset(pass, 0, strlen(pass));
129 xfree(pass);
130 }
Ben Lindstromd0fca422001-03-26 13:44:06 +0000131 return prv;
Damien Millereba71ba2000-04-29 23:57:08 +1000132}
133
Damien Miller874d77b2000-10-14 16:23:11 +1100134#define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
135#define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----"
136#define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
Kevin Stevesef4eea92001-02-05 12:42:17 +0000137#define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb
Damien Millereba71ba2000-04-29 23:57:08 +1000138
Ben Lindstrombba81212001-06-25 05:01:22 +0000139static void
Damien Millereba71ba2000-04-29 23:57:08 +1000140do_convert_to_ssh2(struct passwd *pw)
141{
Ben Lindstrom46c264f2001-04-24 16:56:58 +0000142 Key *k;
Damien Millereba71ba2000-04-29 23:57:08 +1000143 int len;
Ben Lindstrom46c16222000-12-22 01:43:59 +0000144 u_char *blob;
Damien Millereba71ba2000-04-29 23:57:08 +1000145 struct stat st;
146
147 if (!have_identity)
148 ask_filename(pw, "Enter file in which the key is");
149 if (stat(identity_file, &st) < 0) {
150 perror(identity_file);
151 exit(1);
152 }
Ben Lindstrom46c264f2001-04-24 16:56:58 +0000153 if ((k = key_load_public(identity_file, NULL)) == NULL) {
Ben Lindstromd78ae762001-06-05 20:35:09 +0000154 if ((k = load_identity(identity_file)) == NULL) {
Ben Lindstrom46c264f2001-04-24 16:56:58 +0000155 fprintf(stderr, "load failed\n");
156 exit(1);
157 }
Damien Millereba71ba2000-04-29 23:57:08 +1000158 }
Ben Lindstrom46c264f2001-04-24 16:56:58 +0000159 key_to_blob(k, &blob, &len);
Damien Miller874d77b2000-10-14 16:23:11 +1100160 fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
Damien Millereba71ba2000-04-29 23:57:08 +1000161 fprintf(stdout,
Damien Miller874d77b2000-10-14 16:23:11 +1100162 "Comment: \"%d-bit %s, converted from OpenSSH by %s@%s\"\n",
Ben Lindstrom46c264f2001-04-24 16:56:58 +0000163 key_size(k), key_type(k),
Damien Millereba71ba2000-04-29 23:57:08 +1000164 pw->pw_name, hostname);
165 dump_base64(stdout, blob, len);
Damien Miller874d77b2000-10-14 16:23:11 +1100166 fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
Ben Lindstrom46c264f2001-04-24 16:56:58 +0000167 key_free(k);
Damien Millereba71ba2000-04-29 23:57:08 +1000168 xfree(blob);
169 exit(0);
170}
171
Ben Lindstrombba81212001-06-25 05:01:22 +0000172static void
Damien Miller874d77b2000-10-14 16:23:11 +1100173buffer_get_bignum_bits(Buffer *b, BIGNUM *value)
174{
175 int bits = buffer_get_int(b);
176 int bytes = (bits + 7) / 8;
Ben Lindstromd09fcf52001-03-29 00:29:54 +0000177
Damien Miller874d77b2000-10-14 16:23:11 +1100178 if (buffer_len(b) < bytes)
Ben Lindstromd09fcf52001-03-29 00:29:54 +0000179 fatal("buffer_get_bignum_bits: input buffer too small: "
180 "need %d have %d", bytes, buffer_len(b));
Ben Lindstrom46c16222000-12-22 01:43:59 +0000181 BN_bin2bn((u_char *)buffer_ptr(b), bytes, value);
Damien Miller874d77b2000-10-14 16:23:11 +1100182 buffer_consume(b, bytes);
183}
184
Ben Lindstrombba81212001-06-25 05:01:22 +0000185static Key *
Damien Miller874d77b2000-10-14 16:23:11 +1100186do_convert_private_ssh2_from_blob(char *blob, int blen)
187{
188 Buffer b;
Damien Miller874d77b2000-10-14 16:23:11 +1100189 Key *key = NULL;
Damien Miller874d77b2000-10-14 16:23:11 +1100190 char *type, *cipher;
Ben Lindstrome586c4c2001-06-25 05:04:58 +0000191 u_char *sig, data[10] = "abcde12345";
192 int magic, rlen, ktype, i1, i2, i3, i4;
193 u_int slen;
194 u_long e;
Damien Miller874d77b2000-10-14 16:23:11 +1100195
196 buffer_init(&b);
197 buffer_append(&b, blob, blen);
198
199 magic = buffer_get_int(&b);
200 if (magic != SSH_COM_PRIVATE_KEY_MAGIC) {
201 error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC);
202 buffer_free(&b);
203 return NULL;
204 }
Ben Lindstrom34f91882001-06-25 04:47:54 +0000205 i1 = buffer_get_int(&b);
Damien Miller874d77b2000-10-14 16:23:11 +1100206 type = buffer_get_string(&b, NULL);
207 cipher = buffer_get_string(&b, NULL);
Ben Lindstrom34f91882001-06-25 04:47:54 +0000208 i2 = buffer_get_int(&b);
209 i3 = buffer_get_int(&b);
210 i4 = buffer_get_int(&b);
211 debug("ignore (%d %d %d %d)", i1,i2,i3,i4);
Damien Miller874d77b2000-10-14 16:23:11 +1100212 if (strcmp(cipher, "none") != 0) {
213 error("unsupported cipher %s", cipher);
214 xfree(cipher);
215 buffer_free(&b);
Ben Lindstromd09fcf52001-03-29 00:29:54 +0000216 xfree(type);
Damien Miller874d77b2000-10-14 16:23:11 +1100217 return NULL;
218 }
219 xfree(cipher);
220
Ben Lindstromd09fcf52001-03-29 00:29:54 +0000221 if (strstr(type, "dsa")) {
222 ktype = KEY_DSA;
223 } else if (strstr(type, "rsa")) {
224 ktype = KEY_RSA;
225 } else {
226 xfree(type);
Damien Miller874d77b2000-10-14 16:23:11 +1100227 return NULL;
228 }
Ben Lindstromd09fcf52001-03-29 00:29:54 +0000229 key = key_new_private(ktype);
230 xfree(type);
231
232 switch (key->type) {
233 case KEY_DSA:
234 buffer_get_bignum_bits(&b, key->dsa->p);
235 buffer_get_bignum_bits(&b, key->dsa->g);
236 buffer_get_bignum_bits(&b, key->dsa->q);
237 buffer_get_bignum_bits(&b, key->dsa->pub_key);
238 buffer_get_bignum_bits(&b, key->dsa->priv_key);
239 break;
240 case KEY_RSA:
Ben Lindstrom34f91882001-06-25 04:47:54 +0000241 e = buffer_get_char(&b);
242 debug("e %lx", e);
243 if (e < 30) {
244 e <<= 8;
245 e += buffer_get_char(&b);
246 debug("e %lx", e);
247 e <<= 8;
248 e += buffer_get_char(&b);
249 debug("e %lx", e);
250 }
251 if (!BN_set_word(key->rsa->e, e)) {
Ben Lindstromd09fcf52001-03-29 00:29:54 +0000252 buffer_free(&b);
253 key_free(key);
254 return NULL;
255 }
256 buffer_get_bignum_bits(&b, key->rsa->d);
257 buffer_get_bignum_bits(&b, key->rsa->n);
258 buffer_get_bignum_bits(&b, key->rsa->iqmp);
259 buffer_get_bignum_bits(&b, key->rsa->q);
260 buffer_get_bignum_bits(&b, key->rsa->p);
261 generate_additional_parameters(key->rsa);
262 break;
263 }
Damien Miller874d77b2000-10-14 16:23:11 +1100264 rlen = buffer_len(&b);
265 if(rlen != 0)
Ben Lindstromd09fcf52001-03-29 00:29:54 +0000266 error("do_convert_private_ssh2_from_blob: "
267 "remaining bytes in key blob %d", rlen);
Damien Miller874d77b2000-10-14 16:23:11 +1100268 buffer_free(&b);
Ben Lindstromd09fcf52001-03-29 00:29:54 +0000269
Ben Lindstrome586c4c2001-06-25 05:04:58 +0000270 /* try the key */
271 key_sign(key, &sig, &slen, data, sizeof(data));
272 key_verify(key, sig, slen, data, sizeof(data));
273 xfree(sig);
Damien Miller874d77b2000-10-14 16:23:11 +1100274 return key;
275}
276
Ben Lindstrombba81212001-06-25 05:01:22 +0000277static void
Damien Millereba71ba2000-04-29 23:57:08 +1000278do_convert_from_ssh2(struct passwd *pw)
279{
280 Key *k;
281 int blen;
282 char line[1024], *p;
283 char blob[8096];
284 char encoded[8096];
285 struct stat st;
Damien Miller874d77b2000-10-14 16:23:11 +1100286 int escaped = 0, private = 0, ok;
Damien Millereba71ba2000-04-29 23:57:08 +1000287 FILE *fp;
288
289 if (!have_identity)
290 ask_filename(pw, "Enter file in which the key is");
291 if (stat(identity_file, &st) < 0) {
292 perror(identity_file);
293 exit(1);
294 }
295 fp = fopen(identity_file, "r");
296 if (fp == NULL) {
297 perror(identity_file);
298 exit(1);
299 }
300 encoded[0] = '\0';
301 while (fgets(line, sizeof(line), fp)) {
Damien Miller30c3d422000-05-09 11:02:59 +1000302 if (!(p = strchr(line, '\n'))) {
303 fprintf(stderr, "input line too long.\n");
304 exit(1);
305 }
306 if (p > line && p[-1] == '\\')
307 escaped++;
Damien Millereba71ba2000-04-29 23:57:08 +1000308 if (strncmp(line, "----", 4) == 0 ||
309 strstr(line, ": ") != NULL) {
Damien Miller874d77b2000-10-14 16:23:11 +1100310 if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL)
311 private = 1;
Ben Lindstrome586c4c2001-06-25 05:04:58 +0000312 if (strstr(line, " END ") != NULL) {
313 break;
314 }
Ben Lindstrom30358602001-04-24 16:59:28 +0000315 /* fprintf(stderr, "ignore: %s", line); */
Damien Millereba71ba2000-04-29 23:57:08 +1000316 continue;
317 }
Damien Miller30c3d422000-05-09 11:02:59 +1000318 if (escaped) {
319 escaped--;
Ben Lindstrom30358602001-04-24 16:59:28 +0000320 /* fprintf(stderr, "escaped: %s", line); */
Damien Miller30c3d422000-05-09 11:02:59 +1000321 continue;
Damien Millereba71ba2000-04-29 23:57:08 +1000322 }
323 *p = '\0';
324 strlcat(encoded, line, sizeof(encoded));
325 }
Ben Lindstrom46c16222000-12-22 01:43:59 +0000326 blen = uudecode(encoded, (u_char *)blob, sizeof(blob));
Damien Millereba71ba2000-04-29 23:57:08 +1000327 if (blen < 0) {
328 fprintf(stderr, "uudecode failed.\n");
329 exit(1);
330 }
Damien Miller874d77b2000-10-14 16:23:11 +1100331 k = private ?
332 do_convert_private_ssh2_from_blob(blob, blen) :
Damien Miller0bc1bd82000-11-13 22:57:25 +1100333 key_from_blob(blob, blen);
Damien Miller874d77b2000-10-14 16:23:11 +1100334 if (k == NULL) {
335 fprintf(stderr, "decode blob failed.\n");
336 exit(1);
337 }
338 ok = private ?
Ben Lindstromd09fcf52001-03-29 00:29:54 +0000339 (k->type == KEY_DSA ?
340 PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) :
341 PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) :
Damien Miller874d77b2000-10-14 16:23:11 +1100342 key_write(k, stdout);
343 if (!ok) {
344 fprintf(stderr, "key write failed");
345 exit(1);
346 }
Damien Millereba71ba2000-04-29 23:57:08 +1000347 key_free(k);
348 fprintf(stdout, "\n");
349 fclose(fp);
350 exit(0);
351}
352
Ben Lindstrombba81212001-06-25 05:01:22 +0000353static void
Damien Millereba71ba2000-04-29 23:57:08 +1000354do_print_public(struct passwd *pw)
355{
Ben Lindstromd0fca422001-03-26 13:44:06 +0000356 Key *prv;
Damien Millereba71ba2000-04-29 23:57:08 +1000357 struct stat st;
358
359 if (!have_identity)
360 ask_filename(pw, "Enter file in which the key is");
361 if (stat(identity_file, &st) < 0) {
362 perror(identity_file);
363 exit(1);
364 }
Ben Lindstromd78ae762001-06-05 20:35:09 +0000365 prv = load_identity(identity_file);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000366 if (prv == NULL) {
Damien Millereba71ba2000-04-29 23:57:08 +1000367 fprintf(stderr, "load failed\n");
368 exit(1);
369 }
Ben Lindstromd0fca422001-03-26 13:44:06 +0000370 if (!key_write(prv, stdout))
Damien Millereba71ba2000-04-29 23:57:08 +1000371 fprintf(stderr, "key_write failed");
Ben Lindstromd0fca422001-03-26 13:44:06 +0000372 key_free(prv);
Damien Millereba71ba2000-04-29 23:57:08 +1000373 fprintf(stdout, "\n");
374 exit(0);
375}
376
Ben Lindstrombba81212001-06-25 05:01:22 +0000377static void
Damien Miller10f6f6b1999-11-17 17:29:08 +1100378do_fingerprint(struct passwd *pw)
379{
Damien Miller98c7ad62000-03-09 21:27:49 +1100380 FILE *f;
Damien Millereba71ba2000-04-29 23:57:08 +1000381 Key *public;
Ben Lindstrom8fd372b2001-03-12 03:02:17 +0000382 char *comment = NULL, *cp, *ep, line[16*1024], *fp;
Ben Lindstromd0fca422001-03-26 13:44:06 +0000383 int i, skip = 0, num = 1, invalid = 1, rep, fptype;
Damien Miller95def091999-11-25 00:26:21 +1100384 struct stat st;
Damien Miller10f6f6b1999-11-17 17:29:08 +1100385
Ben Lindstromd0fca422001-03-26 13:44:06 +0000386 fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
387 rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
Ben Lindstrom8fd372b2001-03-12 03:02:17 +0000388
Damien Miller95def091999-11-25 00:26:21 +1100389 if (!have_identity)
390 ask_filename(pw, "Enter file in which the key is");
391 if (stat(identity_file, &st) < 0) {
392 perror(identity_file);
393 exit(1);
394 }
Ben Lindstromd0fca422001-03-26 13:44:06 +0000395 public = key_load_public(identity_file, &comment);
396 if (public != NULL) {
397 fp = key_fingerprint(public, fptype, rep);
398 printf("%d %s %s\n", key_size(public), fp, comment);
Damien Miller0bc1bd82000-11-13 22:57:25 +1100399 key_free(public);
400 xfree(comment);
Ben Lindstrom8fd372b2001-03-12 03:02:17 +0000401 xfree(fp);
Damien Miller98c7ad62000-03-09 21:27:49 +1100402 exit(0);
403 }
Ben Lindstromd0fca422001-03-26 13:44:06 +0000404 if (comment)
405 xfree(comment);
Damien Miller98c7ad62000-03-09 21:27:49 +1100406
407 f = fopen(identity_file, "r");
408 if (f != NULL) {
Damien Miller98c7ad62000-03-09 21:27:49 +1100409 while (fgets(line, sizeof(line), f)) {
410 i = strlen(line) - 1;
411 if (line[i] != '\n') {
412 error("line %d too long: %.40s...", num, line);
413 skip = 1;
414 continue;
Damien Miller95def091999-11-25 00:26:21 +1100415 }
Damien Miller98c7ad62000-03-09 21:27:49 +1100416 num++;
417 if (skip) {
418 skip = 0;
419 continue;
420 }
421 line[i] = '\0';
422
423 /* Skip leading whitespace, empty and comment lines. */
424 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
425 ;
426 if (!*cp || *cp == '\n' || *cp == '#')
427 continue ;
428 i = strtol(cp, &ep, 10);
429 if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
430 int quoted = 0;
431 comment = cp;
432 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
433 if (*cp == '\\' && cp[1] == '"')
434 cp++; /* Skip both */
435 else if (*cp == '"')
436 quoted = !quoted;
437 }
438 if (!*cp)
439 continue;
440 *cp++ = '\0';
441 }
442 ep = cp;
Ben Lindstrom2941f112000-12-29 16:50:13 +0000443 public = key_new(KEY_RSA1);
444 if (key_read(public, &cp) != 1) {
445 cp = ep;
446 key_free(public);
447 public = key_new(KEY_UNSPEC);
448 if (key_read(public, &cp) != 1) {
449 key_free(public);
450 continue;
451 }
Damien Miller98c7ad62000-03-09 21:27:49 +1100452 }
Ben Lindstrom2941f112000-12-29 16:50:13 +0000453 comment = *cp ? cp : comment;
Ben Lindstromd0fca422001-03-26 13:44:06 +0000454 fp = key_fingerprint(public, fptype, rep);
Ben Lindstrom8fd372b2001-03-12 03:02:17 +0000455 printf("%d %s %s\n", key_size(public), fp,
Ben Lindstrom2941f112000-12-29 16:50:13 +0000456 comment ? comment : "no comment");
Ben Lindstrom8fd372b2001-03-12 03:02:17 +0000457 xfree(fp);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000458 key_free(public);
Ben Lindstrom2941f112000-12-29 16:50:13 +0000459 invalid = 0;
Damien Miller95def091999-11-25 00:26:21 +1100460 }
Damien Miller98c7ad62000-03-09 21:27:49 +1100461 fclose(f);
Damien Miller95def091999-11-25 00:26:21 +1100462 }
Damien Miller98c7ad62000-03-09 21:27:49 +1100463 if (invalid) {
464 printf("%s is not a valid key file.\n", identity_file);
465 exit(1);
466 }
Damien Miller95def091999-11-25 00:26:21 +1100467 exit(0);
Damien Miller10f6f6b1999-11-17 17:29:08 +1100468}
469
Damien Miller95def091999-11-25 00:26:21 +1100470/*
471 * Perform changing a passphrase. The argument is the passwd structure
472 * for the current user.
473 */
Ben Lindstrombba81212001-06-25 05:01:22 +0000474static void
Damien Miller10f6f6b1999-11-17 17:29:08 +1100475do_change_passphrase(struct passwd *pw)
476{
Damien Miller95def091999-11-25 00:26:21 +1100477 char *comment;
478 char *old_passphrase, *passphrase1, *passphrase2;
479 struct stat st;
Damien Millereba71ba2000-04-29 23:57:08 +1000480 Key *private;
Damien Miller10f6f6b1999-11-17 17:29:08 +1100481
Damien Miller95def091999-11-25 00:26:21 +1100482 if (!have_identity)
483 ask_filename(pw, "Enter file in which the key is");
Damien Miller95def091999-11-25 00:26:21 +1100484 if (stat(identity_file, &st) < 0) {
485 perror(identity_file);
486 exit(1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000487 }
Damien Miller95def091999-11-25 00:26:21 +1100488 /* Try to load the file with empty passphrase. */
Ben Lindstromd0fca422001-03-26 13:44:06 +0000489 private = key_load_private(identity_file, "", &comment);
490 if (private == NULL) {
Damien Miller95def091999-11-25 00:26:21 +1100491 if (identity_passphrase)
492 old_passphrase = xstrdup(identity_passphrase);
493 else
494 old_passphrase = read_passphrase("Enter old passphrase: ", 1);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000495 private = key_load_private(identity_file, old_passphrase , &comment);
496 memset(old_passphrase, 0, strlen(old_passphrase));
497 xfree(old_passphrase);
498 if (private == NULL) {
Damien Miller95def091999-11-25 00:26:21 +1100499 printf("Bad passphrase.\n");
500 exit(1);
501 }
Damien Miller95def091999-11-25 00:26:21 +1100502 }
503 printf("Key has comment '%s'\n", comment);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000504
Damien Miller95def091999-11-25 00:26:21 +1100505 /* Ask the new passphrase (twice). */
506 if (identity_new_passphrase) {
507 passphrase1 = xstrdup(identity_new_passphrase);
508 passphrase2 = NULL;
509 } else {
510 passphrase1 =
511 read_passphrase("Enter new passphrase (empty for no passphrase): ", 1);
512 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
513
514 /* Verify that they are the same. */
515 if (strcmp(passphrase1, passphrase2) != 0) {
516 memset(passphrase1, 0, strlen(passphrase1));
517 memset(passphrase2, 0, strlen(passphrase2));
518 xfree(passphrase1);
519 xfree(passphrase2);
520 printf("Pass phrases do not match. Try again.\n");
521 exit(1);
522 }
523 /* Destroy the other copy. */
524 memset(passphrase2, 0, strlen(passphrase2));
525 xfree(passphrase2);
526 }
527
528 /* Save the file using the new passphrase. */
Ben Lindstromd0fca422001-03-26 13:44:06 +0000529 if (!key_save_private(private, identity_file, passphrase1, comment)) {
Ben Lindstrom15f33862001-04-16 02:00:02 +0000530 printf("Saving the key failed: %s.\n", identity_file);
Damien Miller95def091999-11-25 00:26:21 +1100531 memset(passphrase1, 0, strlen(passphrase1));
532 xfree(passphrase1);
Damien Millereba71ba2000-04-29 23:57:08 +1000533 key_free(private);
Damien Miller95def091999-11-25 00:26:21 +1100534 xfree(comment);
535 exit(1);
536 }
537 /* Destroy the passphrase and the copy of the key in memory. */
538 memset(passphrase1, 0, strlen(passphrase1));
539 xfree(passphrase1);
Damien Millereba71ba2000-04-29 23:57:08 +1000540 key_free(private); /* Destroys contents */
Damien Miller95def091999-11-25 00:26:21 +1100541 xfree(comment);
542
543 printf("Your identification has been saved with the new passphrase.\n");
544 exit(0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000545}
546
Damien Miller95def091999-11-25 00:26:21 +1100547/*
548 * Change the comment of a private key file.
549 */
Ben Lindstrombba81212001-06-25 05:01:22 +0000550static void
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000551do_change_comment(struct passwd *pw)
552{
Ben Lindstrom5fc62702001-03-09 18:19:24 +0000553 char new_comment[1024], *comment, *passphrase;
Ben Lindstromd0fca422001-03-26 13:44:06 +0000554 Key *private;
555 Key *public;
Damien Miller95def091999-11-25 00:26:21 +1100556 struct stat st;
557 FILE *f;
Ben Lindstrom5fc62702001-03-09 18:19:24 +0000558 int fd;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000559
Damien Miller95def091999-11-25 00:26:21 +1100560 if (!have_identity)
561 ask_filename(pw, "Enter file in which the key is");
Damien Miller95def091999-11-25 00:26:21 +1100562 if (stat(identity_file, &st) < 0) {
563 perror(identity_file);
564 exit(1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000565 }
Ben Lindstromd0fca422001-03-26 13:44:06 +0000566 private = key_load_private(identity_file, "", &comment);
567 if (private == NULL) {
Damien Miller95def091999-11-25 00:26:21 +1100568 if (identity_passphrase)
569 passphrase = xstrdup(identity_passphrase);
570 else if (identity_new_passphrase)
571 passphrase = xstrdup(identity_new_passphrase);
572 else
573 passphrase = read_passphrase("Enter passphrase: ", 1);
574 /* Try to load using the passphrase. */
Ben Lindstromd0fca422001-03-26 13:44:06 +0000575 private = key_load_private(identity_file, passphrase, &comment);
576 if (private == NULL) {
Damien Miller95def091999-11-25 00:26:21 +1100577 memset(passphrase, 0, strlen(passphrase));
578 xfree(passphrase);
579 printf("Bad passphrase.\n");
580 exit(1);
581 }
Ben Lindstromd0fca422001-03-26 13:44:06 +0000582 } else {
583 passphrase = xstrdup("");
Damien Miller95def091999-11-25 00:26:21 +1100584 }
Ben Lindstromd0fca422001-03-26 13:44:06 +0000585 if (private->type != KEY_RSA1) {
586 fprintf(stderr, "Comments are only supported for RSA1 keys.\n");
587 key_free(private);
588 exit(1);
589 }
Damien Miller95def091999-11-25 00:26:21 +1100590 printf("Key now has comment '%s'\n", comment);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000591
Damien Miller95def091999-11-25 00:26:21 +1100592 if (identity_comment) {
593 strlcpy(new_comment, identity_comment, sizeof(new_comment));
594 } else {
595 printf("Enter new comment: ");
596 fflush(stdout);
597 if (!fgets(new_comment, sizeof(new_comment), stdin)) {
598 memset(passphrase, 0, strlen(passphrase));
Damien Millereba71ba2000-04-29 23:57:08 +1000599 key_free(private);
Damien Miller95def091999-11-25 00:26:21 +1100600 exit(1);
601 }
Damien Miller95def091999-11-25 00:26:21 +1100602 if (strchr(new_comment, '\n'))
603 *strchr(new_comment, '\n') = 0;
604 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000605
Damien Miller95def091999-11-25 00:26:21 +1100606 /* Save the file using the new passphrase. */
Ben Lindstromd0fca422001-03-26 13:44:06 +0000607 if (!key_save_private(private, identity_file, passphrase, new_comment)) {
Ben Lindstrom15f33862001-04-16 02:00:02 +0000608 printf("Saving the key failed: %s.\n", identity_file);
Damien Miller95def091999-11-25 00:26:21 +1100609 memset(passphrase, 0, strlen(passphrase));
610 xfree(passphrase);
Damien Millereba71ba2000-04-29 23:57:08 +1000611 key_free(private);
Damien Miller95def091999-11-25 00:26:21 +1100612 xfree(comment);
613 exit(1);
614 }
Damien Miller95def091999-11-25 00:26:21 +1100615 memset(passphrase, 0, strlen(passphrase));
616 xfree(passphrase);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000617 public = key_from_private(private);
Damien Millereba71ba2000-04-29 23:57:08 +1000618 key_free(private);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000619
Damien Miller95def091999-11-25 00:26:21 +1100620 strlcat(identity_file, ".pub", sizeof(identity_file));
Ben Lindstrom5fc62702001-03-09 18:19:24 +0000621 fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
622 if (fd == -1) {
Damien Miller95def091999-11-25 00:26:21 +1100623 printf("Could not save your public key in %s\n", identity_file);
624 exit(1);
625 }
Ben Lindstrom5fc62702001-03-09 18:19:24 +0000626 f = fdopen(fd, "w");
627 if (f == NULL) {
628 printf("fdopen %s failed", identity_file);
629 exit(1);
630 }
Damien Millereba71ba2000-04-29 23:57:08 +1000631 if (!key_write(public, f))
632 fprintf(stderr, "write key failed");
633 key_free(public);
634 fprintf(f, " %s\n", new_comment);
Damien Miller95def091999-11-25 00:26:21 +1100635 fclose(f);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000636
Damien Miller95def091999-11-25 00:26:21 +1100637 xfree(comment);
638
639 printf("The comment in your key file has been changed.\n");
640 exit(0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000641}
642
Ben Lindstrombba81212001-06-25 05:01:22 +0000643static void
Damien Miller431f66b1999-11-21 18:31:57 +1100644usage(void)
645{
Ben Lindstrom2857d9c2001-04-22 17:19:46 +0000646 printf("Usage: %s [-ceilpqyB] [-t type] [-b bits] [-f file] [-C comment] "
Ben Lindstromb7c92322001-03-05 05:10:52 +0000647 "[-N new-pass] [-P pass]\n", __progname);
Damien Miller95def091999-11-25 00:26:21 +1100648 exit(1);
Damien Miller431f66b1999-11-21 18:31:57 +1100649}
650
Damien Miller95def091999-11-25 00:26:21 +1100651/*
652 * Main program for key management.
653 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000654int
655main(int ac, char **av)
656{
Damien Miller95def091999-11-25 00:26:21 +1100657 char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
Ben Lindstrom5fc62702001-03-09 18:19:24 +0000658 Key *private, *public;
Damien Miller95def091999-11-25 00:26:21 +1100659 struct passwd *pw;
Ben Lindstrom5fc62702001-03-09 18:19:24 +0000660 int opt, type, fd;
Damien Miller95def091999-11-25 00:26:21 +1100661 struct stat st;
662 FILE *f;
Damien Miller0bc1bd82000-11-13 22:57:25 +1100663
Damien Miller95def091999-11-25 00:26:21 +1100664 extern int optind;
665 extern char *optarg;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000666
Ben Lindstrom49a79c02000-11-17 03:47:20 +0000667 __progname = get_progname(av[0]);
Damien Millerf9b625c2000-07-09 22:42:32 +1000668 init_rng();
Damien Miller60bc5172001-03-19 09:38:15 +1100669 seed_rng();
Damien Millerf9b625c2000-07-09 22:42:32 +1000670
Damien Millerd3a18572000-06-07 19:55:44 +1000671 SSLeay_add_all_algorithms();
Damien Millereba71ba2000-04-29 23:57:08 +1000672
Damien Miller5428f641999-11-25 11:54:57 +1100673 /* we need this for the home * directory. */
Damien Miller95def091999-11-25 00:26:21 +1100674 pw = getpwuid(getuid());
675 if (!pw) {
676 printf("You don't exist, go away!\n");
677 exit(1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000678 }
Damien Millereba71ba2000-04-29 23:57:08 +1000679 if (gethostname(hostname, sizeof(hostname)) < 0) {
680 perror("gethostname");
681 exit(1);
682 }
Damien Miller5428f641999-11-25 11:54:57 +1100683
Ben Lindstrom5a707822001-04-22 17:15:46 +0000684 while ((opt = getopt(ac, av, "deiqpclBRxXyb:f:t:P:N:C:")) != -1) {
Damien Miller95def091999-11-25 00:26:21 +1100685 switch (opt) {
686 case 'b':
687 bits = atoi(optarg);
688 if (bits < 512 || bits > 32768) {
689 printf("Bits has bad value.\n");
690 exit(1);
691 }
692 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000693
Damien Miller95def091999-11-25 00:26:21 +1100694 case 'l':
695 print_fingerprint = 1;
696 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000697
Ben Lindstrom8fd372b2001-03-12 03:02:17 +0000698 case 'B':
699 print_bubblebabble = 1;
700 break;
701
Damien Miller95def091999-11-25 00:26:21 +1100702 case 'p':
703 change_passphrase = 1;
704 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000705
Damien Miller95def091999-11-25 00:26:21 +1100706 case 'c':
707 change_comment = 1;
708 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000709
Damien Miller95def091999-11-25 00:26:21 +1100710 case 'f':
711 strlcpy(identity_file, optarg, sizeof(identity_file));
712 have_identity = 1;
713 break;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000714
Damien Miller95def091999-11-25 00:26:21 +1100715 case 'P':
716 identity_passphrase = optarg;
717 break;
718
719 case 'N':
720 identity_new_passphrase = optarg;
721 break;
722
723 case 'C':
724 identity_comment = optarg;
725 break;
726
727 case 'q':
728 quiet = 1;
729 break;
730
Damien Millereba71ba2000-04-29 23:57:08 +1000731 case 'R':
Damien Miller0bc1bd82000-11-13 22:57:25 +1100732 /* unused */
733 exit(0);
Damien Millereba71ba2000-04-29 23:57:08 +1000734 break;
735
Ben Lindstrom5a707822001-04-22 17:15:46 +0000736 case 'e':
Damien Millereba71ba2000-04-29 23:57:08 +1000737 case 'x':
Ben Lindstrom5a707822001-04-22 17:15:46 +0000738 /* export key */
Damien Millereba71ba2000-04-29 23:57:08 +1000739 convert_to_ssh2 = 1;
740 break;
741
Ben Lindstrom5a707822001-04-22 17:15:46 +0000742 case 'i':
Damien Millereba71ba2000-04-29 23:57:08 +1000743 case 'X':
Ben Lindstrom5a707822001-04-22 17:15:46 +0000744 /* import key */
Damien Millereba71ba2000-04-29 23:57:08 +1000745 convert_from_ssh2 = 1;
746 break;
747
748 case 'y':
749 print_public = 1;
750 break;
751
752 case 'd':
Damien Miller0bc1bd82000-11-13 22:57:25 +1100753 key_type_name = "dsa";
Damien Millereba71ba2000-04-29 23:57:08 +1000754 break;
755
Damien Miller0bc1bd82000-11-13 22:57:25 +1100756 case 't':
757 key_type_name = optarg;
Damien Miller0bc1bd82000-11-13 22:57:25 +1100758 break;
759
Damien Miller95def091999-11-25 00:26:21 +1100760 case '?':
761 default:
762 usage();
763 }
764 }
765 if (optind < ac) {
766 printf("Too many arguments.\n");
767 usage();
768 }
769 if (change_passphrase && change_comment) {
770 printf("Can only have one of -p and -c.\n");
771 usage();
772 }
Ben Lindstrom8fd372b2001-03-12 03:02:17 +0000773 if (print_fingerprint || print_bubblebabble)
Damien Miller95def091999-11-25 00:26:21 +1100774 do_fingerprint(pw);
Damien Miller95def091999-11-25 00:26:21 +1100775 if (change_passphrase)
776 do_change_passphrase(pw);
Damien Miller95def091999-11-25 00:26:21 +1100777 if (change_comment)
778 do_change_comment(pw);
Damien Millereba71ba2000-04-29 23:57:08 +1000779 if (convert_to_ssh2)
780 do_convert_to_ssh2(pw);
781 if (convert_from_ssh2)
782 do_convert_from_ssh2(pw);
783 if (print_public)
784 do_print_public(pw);
Damien Miller95def091999-11-25 00:26:21 +1100785
786 arc4random_stir();
787
Damien Millere39cacc2000-11-29 12:18:44 +1100788 type = key_type_from_name(key_type_name);
789 if (type == KEY_UNSPEC) {
790 fprintf(stderr, "unknown key type %s\n", key_type_name);
791 exit(1);
Damien Millereba71ba2000-04-29 23:57:08 +1000792 }
Damien Miller0bc1bd82000-11-13 22:57:25 +1100793 if (!quiet)
Damien Millere39cacc2000-11-29 12:18:44 +1100794 printf("Generating public/private %s key pair.\n", key_type_name);
Damien Miller0bc1bd82000-11-13 22:57:25 +1100795 private = key_generate(type, bits);
796 if (private == NULL) {
797 fprintf(stderr, "key_generate failed");
798 exit(1);
799 }
800 public = key_from_private(private);
Damien Miller95def091999-11-25 00:26:21 +1100801
802 if (!have_identity)
803 ask_filename(pw, "Enter file in which to save the key");
804
805 /* Create ~/.ssh directory if it doesn\'t already exist. */
Ben Lindstrom226cfa02001-01-22 05:34:40 +0000806 snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR);
Damien Miller95def091999-11-25 00:26:21 +1100807 if (strstr(identity_file, dotsshdir) != NULL &&
808 stat(dotsshdir, &st) < 0) {
Damien Millerbe484b52000-07-15 14:14:16 +1000809 if (mkdir(dotsshdir, 0700) < 0)
Damien Miller95def091999-11-25 00:26:21 +1100810 error("Could not create directory '%s'.", dotsshdir);
811 else if (!quiet)
812 printf("Created directory '%s'.\n", dotsshdir);
813 }
814 /* If the file already exists, ask the user to confirm. */
815 if (stat(identity_file, &st) >= 0) {
816 char yesno[3];
817 printf("%s already exists.\n", identity_file);
818 printf("Overwrite (y/n)? ");
819 fflush(stdout);
820 if (fgets(yesno, sizeof(yesno), stdin) == NULL)
821 exit(1);
822 if (yesno[0] != 'y' && yesno[0] != 'Y')
823 exit(1);
824 }
825 /* Ask for a passphrase (twice). */
826 if (identity_passphrase)
827 passphrase1 = xstrdup(identity_passphrase);
828 else if (identity_new_passphrase)
829 passphrase1 = xstrdup(identity_new_passphrase);
830 else {
831passphrase_again:
832 passphrase1 =
833 read_passphrase("Enter passphrase (empty for no passphrase): ", 1);
834 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
835 if (strcmp(passphrase1, passphrase2) != 0) {
836 /* The passphrases do not match. Clear them and retry. */
837 memset(passphrase1, 0, strlen(passphrase1));
838 memset(passphrase2, 0, strlen(passphrase2));
839 xfree(passphrase1);
840 xfree(passphrase2);
841 printf("Passphrases do not match. Try again.\n");
842 goto passphrase_again;
843 }
844 /* Clear the other copy of the passphrase. */
845 memset(passphrase2, 0, strlen(passphrase2));
846 xfree(passphrase2);
847 }
848
Damien Miller95def091999-11-25 00:26:21 +1100849 if (identity_comment) {
850 strlcpy(comment, identity_comment, sizeof(comment));
851 } else {
Damien Miller4af51302000-04-16 11:18:38 +1000852 /* Create default commend field for the passphrase. */
Damien Miller95def091999-11-25 00:26:21 +1100853 snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
854 }
855
856 /* Save the key with the given passphrase and comment. */
Ben Lindstromd0fca422001-03-26 13:44:06 +0000857 if (!key_save_private(private, identity_file, passphrase1, comment)) {
Ben Lindstrom15f33862001-04-16 02:00:02 +0000858 printf("Saving the key failed: %s.\n", identity_file);
Damien Miller95def091999-11-25 00:26:21 +1100859 memset(passphrase1, 0, strlen(passphrase1));
860 xfree(passphrase1);
861 exit(1);
862 }
863 /* Clear the passphrase. */
864 memset(passphrase1, 0, strlen(passphrase1));
865 xfree(passphrase1);
866
867 /* Clear the private key and the random number generator. */
Damien Miller0bc1bd82000-11-13 22:57:25 +1100868 key_free(private);
Damien Miller95def091999-11-25 00:26:21 +1100869 arc4random_stir();
870
871 if (!quiet)
872 printf("Your identification has been saved in %s.\n", identity_file);
873
Damien Miller95def091999-11-25 00:26:21 +1100874 strlcat(identity_file, ".pub", sizeof(identity_file));
Ben Lindstrom5fc62702001-03-09 18:19:24 +0000875 fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
876 if (fd == -1) {
Damien Miller95def091999-11-25 00:26:21 +1100877 printf("Could not save your public key in %s\n", identity_file);
878 exit(1);
879 }
Ben Lindstrom5fc62702001-03-09 18:19:24 +0000880 f = fdopen(fd, "w");
881 if (f == NULL) {
882 printf("fdopen %s failed", identity_file);
883 exit(1);
884 }
Damien Millereba71ba2000-04-29 23:57:08 +1000885 if (!key_write(public, f))
886 fprintf(stderr, "write key failed");
887 fprintf(f, " %s\n", comment);
Damien Miller95def091999-11-25 00:26:21 +1100888 fclose(f);
889
890 if (!quiet) {
Ben Lindstromcfccef92001-03-13 04:57:58 +0000891 char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
Damien Millereba71ba2000-04-29 23:57:08 +1000892 printf("Your public key has been saved in %s.\n",
893 identity_file);
Damien Miller95def091999-11-25 00:26:21 +1100894 printf("The key fingerprint is:\n");
Ben Lindstromcfccef92001-03-13 04:57:58 +0000895 printf("%s %s\n", fp, comment);
896 xfree(fp);
Damien Miller95def091999-11-25 00:26:21 +1100897 }
Damien Millereba71ba2000-04-29 23:57:08 +1000898
899 key_free(public);
Damien Miller95def091999-11-25 00:26:21 +1100900 exit(0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000901}