ssh-keygen.c revision 1.3 1 1.3 christos /* $NetBSD: ssh-keygen.c,v 1.3 2009/12/27 01:40:47 christos Exp $ */
2 1.3 christos /* $OpenBSD: ssh-keygen.c,v 1.174 2009/06/22 05:39:28 dtucker Exp $ */
3 1.1 christos /*
4 1.1 christos * Author: Tatu Ylonen <ylo (at) cs.hut.fi>
5 1.1 christos * Copyright (c) 1994 Tatu Ylonen <ylo (at) cs.hut.fi>, Espoo, Finland
6 1.1 christos * All rights reserved
7 1.1 christos * Identity and host key generation and maintenance.
8 1.1 christos *
9 1.1 christos * As far as I am concerned, the code I have written for this software
10 1.1 christos * can be used freely for any purpose. Any derived versions of this
11 1.1 christos * software must be clearly marked as such, and if the derived work is
12 1.1 christos * incompatible with the protocol description in the RFC file, it must be
13 1.1 christos * called by a name other than "ssh" or "Secure Shell".
14 1.1 christos */
15 1.1 christos
16 1.2 christos #include "includes.h"
17 1.3 christos __RCSID("$NetBSD: ssh-keygen.c,v 1.3 2009/12/27 01:40:47 christos Exp $");
18 1.1 christos #include <sys/types.h>
19 1.3 christos #include <sys/socket.h>
20 1.1 christos #include <sys/stat.h>
21 1.1 christos #include <sys/param.h>
22 1.1 christos
23 1.1 christos #include <openssl/evp.h>
24 1.1 christos #include <openssl/pem.h>
25 1.1 christos
26 1.1 christos #include <errno.h>
27 1.1 christos #include <fcntl.h>
28 1.1 christos #include <pwd.h>
29 1.1 christos #include <stdio.h>
30 1.1 christos #include <stdlib.h>
31 1.1 christos #include <string.h>
32 1.1 christos #include <unistd.h>
33 1.1 christos
34 1.1 christos #include "xmalloc.h"
35 1.1 christos #include "key.h"
36 1.1 christos #include "rsa.h"
37 1.1 christos #include "authfile.h"
38 1.1 christos #include "uuencode.h"
39 1.1 christos #include "buffer.h"
40 1.1 christos #include "pathnames.h"
41 1.1 christos #include "log.h"
42 1.1 christos #include "misc.h"
43 1.1 christos #include "match.h"
44 1.1 christos #include "hostfile.h"
45 1.1 christos #include "dns.h"
46 1.1 christos
47 1.1 christos #ifdef SMARTCARD
48 1.1 christos #include "scard.h"
49 1.1 christos #endif
50 1.1 christos
51 1.1 christos /* Number of bits in the RSA/DSA key. This value can be set on the command line. */
52 1.1 christos #define DEFAULT_BITS 2048
53 1.1 christos #define DEFAULT_BITS_DSA 1024
54 1.1 christos u_int32_t bits = 0;
55 1.1 christos
56 1.1 christos /*
57 1.1 christos * Flag indicating that we just want to change the passphrase. This can be
58 1.1 christos * set on the command line.
59 1.1 christos */
60 1.1 christos int change_passphrase = 0;
61 1.1 christos
62 1.1 christos /*
63 1.1 christos * Flag indicating that we just want to change the comment. This can be set
64 1.1 christos * on the command line.
65 1.1 christos */
66 1.1 christos int change_comment = 0;
67 1.1 christos
68 1.1 christos int quiet = 0;
69 1.1 christos
70 1.1 christos int log_level = SYSLOG_LEVEL_INFO;
71 1.1 christos
72 1.1 christos /* Flag indicating that we want to hash a known_hosts file */
73 1.1 christos int hash_hosts = 0;
74 1.1 christos /* Flag indicating that we want lookup a host in known_hosts file */
75 1.1 christos int find_host = 0;
76 1.1 christos /* Flag indicating that we want to delete a host from a known_hosts file */
77 1.1 christos int delete_host = 0;
78 1.1 christos
79 1.1 christos /* Flag indicating that we just want to see the key fingerprint */
80 1.1 christos int print_fingerprint = 0;
81 1.1 christos int print_bubblebabble = 0;
82 1.1 christos
83 1.1 christos /* The identity file name, given on the command line or entered by the user. */
84 1.1 christos char identity_file[1024];
85 1.1 christos int have_identity = 0;
86 1.1 christos
87 1.1 christos /* This is set to the passphrase if given on the command line. */
88 1.1 christos char *identity_passphrase = NULL;
89 1.1 christos
90 1.1 christos /* This is set to the new passphrase if given on the command line. */
91 1.1 christos char *identity_new_passphrase = NULL;
92 1.1 christos
93 1.1 christos /* This is set to the new comment if given on the command line. */
94 1.1 christos char *identity_comment = NULL;
95 1.1 christos
96 1.1 christos /* Dump public key file in format used by real and the original SSH 2 */
97 1.1 christos int convert_to_ssh2 = 0;
98 1.1 christos int convert_from_ssh2 = 0;
99 1.1 christos int print_public = 0;
100 1.1 christos int print_generic = 0;
101 1.1 christos
102 1.1 christos char *key_type_name = NULL;
103 1.1 christos
104 1.1 christos /* argv0 */
105 1.1 christos extern char *__progname;
106 1.1 christos
107 1.1 christos char hostname[MAXHOSTNAMELEN];
108 1.1 christos
109 1.1 christos /* moduli.c */
110 1.1 christos int gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *);
111 1.1 christos int prime_test(FILE *, FILE *, u_int32_t, u_int32_t);
112 1.1 christos
113 1.1 christos static void
114 1.1 christos ask_filename(struct passwd *pw, const char *prompt)
115 1.1 christos {
116 1.1 christos char buf[1024];
117 1.1 christos char *name = NULL;
118 1.1 christos
119 1.1 christos if (key_type_name == NULL)
120 1.1 christos name = _PATH_SSH_CLIENT_ID_RSA;
121 1.1 christos else {
122 1.1 christos switch (key_type_from_name(key_type_name)) {
123 1.1 christos case KEY_RSA1:
124 1.1 christos name = _PATH_SSH_CLIENT_IDENTITY;
125 1.1 christos break;
126 1.1 christos case KEY_DSA:
127 1.1 christos name = _PATH_SSH_CLIENT_ID_DSA;
128 1.1 christos break;
129 1.1 christos case KEY_RSA:
130 1.1 christos name = _PATH_SSH_CLIENT_ID_RSA;
131 1.1 christos break;
132 1.1 christos default:
133 1.1 christos fprintf(stderr, "bad key type\n");
134 1.1 christos exit(1);
135 1.1 christos break;
136 1.1 christos }
137 1.1 christos }
138 1.1 christos snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name);
139 1.1 christos fprintf(stderr, "%s (%s): ", prompt, identity_file);
140 1.1 christos if (fgets(buf, sizeof(buf), stdin) == NULL)
141 1.1 christos exit(1);
142 1.1 christos buf[strcspn(buf, "\n")] = '\0';
143 1.1 christos if (strcmp(buf, "") != 0)
144 1.1 christos strlcpy(identity_file, buf, sizeof(identity_file));
145 1.1 christos have_identity = 1;
146 1.1 christos }
147 1.1 christos
148 1.1 christos static Key *
149 1.1 christos load_identity(char *filename)
150 1.1 christos {
151 1.1 christos char *pass;
152 1.1 christos Key *prv;
153 1.1 christos
154 1.1 christos prv = key_load_private(filename, "", NULL);
155 1.1 christos if (prv == NULL) {
156 1.1 christos if (identity_passphrase)
157 1.1 christos pass = xstrdup(identity_passphrase);
158 1.1 christos else
159 1.1 christos pass = read_passphrase("Enter passphrase: ",
160 1.1 christos RP_ALLOW_STDIN);
161 1.1 christos prv = key_load_private(filename, pass, NULL);
162 1.1 christos memset(pass, 0, strlen(pass));
163 1.1 christos xfree(pass);
164 1.1 christos }
165 1.1 christos return prv;
166 1.1 christos }
167 1.1 christos
168 1.1 christos #define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
169 1.1 christos #define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----"
170 1.1 christos #define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
171 1.1 christos #define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb
172 1.1 christos
173 1.1 christos static void
174 1.1 christos do_convert_to_ssh2(struct passwd *pw)
175 1.1 christos {
176 1.1 christos Key *k;
177 1.1 christos u_int len;
178 1.1 christos u_char *blob;
179 1.1 christos struct stat st;
180 1.1 christos
181 1.1 christos if (!have_identity)
182 1.1 christos ask_filename(pw, "Enter file in which the key is");
183 1.1 christos if (stat(identity_file, &st) < 0) {
184 1.1 christos perror(identity_file);
185 1.1 christos exit(1);
186 1.1 christos }
187 1.1 christos if ((k = key_load_public(identity_file, NULL)) == NULL) {
188 1.1 christos if ((k = load_identity(identity_file)) == NULL) {
189 1.1 christos fprintf(stderr, "load failed\n");
190 1.1 christos exit(1);
191 1.1 christos }
192 1.1 christos }
193 1.1 christos if (k->type == KEY_RSA1) {
194 1.1 christos fprintf(stderr, "version 1 keys are not supported\n");
195 1.1 christos exit(1);
196 1.1 christos }
197 1.1 christos if (key_to_blob(k, &blob, &len) <= 0) {
198 1.1 christos fprintf(stderr, "key_to_blob failed\n");
199 1.1 christos exit(1);
200 1.1 christos }
201 1.1 christos fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
202 1.1 christos fprintf(stdout,
203 1.1 christos "Comment: \"%u-bit %s, converted from OpenSSH by %s@%s\"\n",
204 1.1 christos key_size(k), key_type(k),
205 1.1 christos pw->pw_name, hostname);
206 1.1 christos dump_base64(stdout, blob, len);
207 1.1 christos fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
208 1.1 christos key_free(k);
209 1.1 christos xfree(blob);
210 1.1 christos exit(0);
211 1.1 christos }
212 1.1 christos
213 1.1 christos static void
214 1.1 christos buffer_get_bignum_bits(Buffer *b, BIGNUM *value)
215 1.1 christos {
216 1.1 christos u_int bignum_bits = buffer_get_int(b);
217 1.1 christos u_int bytes = (bignum_bits + 7) / 8;
218 1.1 christos
219 1.1 christos if (buffer_len(b) < bytes)
220 1.1 christos fatal("buffer_get_bignum_bits: input buffer too small: "
221 1.1 christos "need %d have %d", bytes, buffer_len(b));
222 1.1 christos if (BN_bin2bn(buffer_ptr(b), bytes, value) == NULL)
223 1.1 christos fatal("buffer_get_bignum_bits: BN_bin2bn failed");
224 1.1 christos buffer_consume(b, bytes);
225 1.1 christos }
226 1.1 christos
227 1.1 christos static Key *
228 1.1 christos do_convert_private_ssh2_from_blob(u_char *blob, u_int blen)
229 1.1 christos {
230 1.1 christos Buffer b;
231 1.1 christos Key *key = NULL;
232 1.1 christos char *type, *cipher;
233 1.1 christos u_char *sig, data[] = "abcde12345";
234 1.1 christos int magic, rlen, ktype, i1, i2, i3, i4;
235 1.1 christos u_int slen;
236 1.1 christos u_long e;
237 1.1 christos
238 1.1 christos buffer_init(&b);
239 1.1 christos buffer_append(&b, blob, blen);
240 1.1 christos
241 1.1 christos magic = buffer_get_int(&b);
242 1.1 christos if (magic != SSH_COM_PRIVATE_KEY_MAGIC) {
243 1.1 christos error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC);
244 1.1 christos buffer_free(&b);
245 1.1 christos return NULL;
246 1.1 christos }
247 1.1 christos i1 = buffer_get_int(&b);
248 1.1 christos type = buffer_get_string(&b, NULL);
249 1.1 christos cipher = buffer_get_string(&b, NULL);
250 1.1 christos i2 = buffer_get_int(&b);
251 1.1 christos i3 = buffer_get_int(&b);
252 1.1 christos i4 = buffer_get_int(&b);
253 1.1 christos debug("ignore (%d %d %d %d)", i1, i2, i3, i4);
254 1.1 christos if (strcmp(cipher, "none") != 0) {
255 1.1 christos error("unsupported cipher %s", cipher);
256 1.1 christos xfree(cipher);
257 1.1 christos buffer_free(&b);
258 1.1 christos xfree(type);
259 1.1 christos return NULL;
260 1.1 christos }
261 1.1 christos xfree(cipher);
262 1.1 christos
263 1.1 christos if (strstr(type, "dsa")) {
264 1.1 christos ktype = KEY_DSA;
265 1.1 christos } else if (strstr(type, "rsa")) {
266 1.1 christos ktype = KEY_RSA;
267 1.1 christos } else {
268 1.1 christos buffer_free(&b);
269 1.1 christos xfree(type);
270 1.1 christos return NULL;
271 1.1 christos }
272 1.1 christos key = key_new_private(ktype);
273 1.1 christos xfree(type);
274 1.1 christos
275 1.1 christos switch (key->type) {
276 1.1 christos case KEY_DSA:
277 1.1 christos buffer_get_bignum_bits(&b, key->dsa->p);
278 1.1 christos buffer_get_bignum_bits(&b, key->dsa->g);
279 1.1 christos buffer_get_bignum_bits(&b, key->dsa->q);
280 1.1 christos buffer_get_bignum_bits(&b, key->dsa->pub_key);
281 1.1 christos buffer_get_bignum_bits(&b, key->dsa->priv_key);
282 1.1 christos break;
283 1.1 christos case KEY_RSA:
284 1.1 christos e = buffer_get_char(&b);
285 1.1 christos debug("e %lx", e);
286 1.1 christos if (e < 30) {
287 1.1 christos e <<= 8;
288 1.1 christos e += buffer_get_char(&b);
289 1.1 christos debug("e %lx", e);
290 1.1 christos e <<= 8;
291 1.1 christos e += buffer_get_char(&b);
292 1.1 christos debug("e %lx", e);
293 1.1 christos }
294 1.1 christos if (!BN_set_word(key->rsa->e, e)) {
295 1.1 christos buffer_free(&b);
296 1.1 christos key_free(key);
297 1.1 christos return NULL;
298 1.1 christos }
299 1.1 christos buffer_get_bignum_bits(&b, key->rsa->d);
300 1.1 christos buffer_get_bignum_bits(&b, key->rsa->n);
301 1.1 christos buffer_get_bignum_bits(&b, key->rsa->iqmp);
302 1.1 christos buffer_get_bignum_bits(&b, key->rsa->q);
303 1.1 christos buffer_get_bignum_bits(&b, key->rsa->p);
304 1.1 christos rsa_generate_additional_parameters(key->rsa);
305 1.1 christos break;
306 1.1 christos }
307 1.1 christos rlen = buffer_len(&b);
308 1.1 christos if (rlen != 0)
309 1.1 christos error("do_convert_private_ssh2_from_blob: "
310 1.1 christos "remaining bytes in key blob %d", rlen);
311 1.1 christos buffer_free(&b);
312 1.1 christos
313 1.1 christos /* try the key */
314 1.1 christos key_sign(key, &sig, &slen, data, sizeof(data));
315 1.1 christos key_verify(key, sig, slen, data, sizeof(data));
316 1.1 christos xfree(sig);
317 1.1 christos return key;
318 1.1 christos }
319 1.1 christos
320 1.1 christos static int
321 1.1 christos get_line(FILE *fp, char *line, size_t len)
322 1.1 christos {
323 1.1 christos int c;
324 1.1 christos size_t pos = 0;
325 1.1 christos
326 1.1 christos line[0] = '\0';
327 1.1 christos while ((c = fgetc(fp)) != EOF) {
328 1.1 christos if (pos >= len - 1) {
329 1.1 christos fprintf(stderr, "input line too long.\n");
330 1.1 christos exit(1);
331 1.1 christos }
332 1.1 christos switch (c) {
333 1.1 christos case '\r':
334 1.1 christos c = fgetc(fp);
335 1.1 christos if (c != EOF && c != '\n' && ungetc(c, fp) == EOF) {
336 1.1 christos fprintf(stderr, "unget: %s\n", strerror(errno));
337 1.1 christos exit(1);
338 1.1 christos }
339 1.1 christos return pos;
340 1.1 christos case '\n':
341 1.1 christos return pos;
342 1.1 christos }
343 1.1 christos line[pos++] = c;
344 1.1 christos line[pos] = '\0';
345 1.1 christos }
346 1.1 christos /* We reached EOF */
347 1.1 christos return -1;
348 1.1 christos }
349 1.1 christos
350 1.1 christos static void
351 1.1 christos do_convert_from_ssh2(struct passwd *pw)
352 1.1 christos {
353 1.1 christos Key *k;
354 1.1 christos int blen;
355 1.1 christos u_int len;
356 1.1 christos char line[1024];
357 1.1 christos u_char blob[8096];
358 1.1 christos char encoded[8096];
359 1.1 christos struct stat st;
360 1.1 christos int escaped = 0, private = 0, ok;
361 1.1 christos FILE *fp;
362 1.1 christos
363 1.1 christos if (!have_identity)
364 1.1 christos ask_filename(pw, "Enter file in which the key is");
365 1.1 christos if (stat(identity_file, &st) < 0) {
366 1.1 christos perror(identity_file);
367 1.1 christos exit(1);
368 1.1 christos }
369 1.1 christos fp = fopen(identity_file, "r");
370 1.1 christos if (fp == NULL) {
371 1.1 christos perror(identity_file);
372 1.1 christos exit(1);
373 1.1 christos }
374 1.1 christos encoded[0] = '\0';
375 1.1 christos while ((blen = get_line(fp, line, sizeof(line))) != -1) {
376 1.1 christos if (line[blen - 1] == '\\')
377 1.1 christos escaped++;
378 1.1 christos if (strncmp(line, "----", 4) == 0 ||
379 1.1 christos strstr(line, ": ") != NULL) {
380 1.1 christos if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL)
381 1.1 christos private = 1;
382 1.1 christos if (strstr(line, " END ") != NULL) {
383 1.1 christos break;
384 1.1 christos }
385 1.1 christos /* fprintf(stderr, "ignore: %s", line); */
386 1.1 christos continue;
387 1.1 christos }
388 1.1 christos if (escaped) {
389 1.1 christos escaped--;
390 1.1 christos /* fprintf(stderr, "escaped: %s", line); */
391 1.1 christos continue;
392 1.1 christos }
393 1.1 christos strlcat(encoded, line, sizeof(encoded));
394 1.1 christos }
395 1.1 christos len = strlen(encoded);
396 1.1 christos if (((len % 4) == 3) &&
397 1.1 christos (encoded[len-1] == '=') &&
398 1.1 christos (encoded[len-2] == '=') &&
399 1.1 christos (encoded[len-3] == '='))
400 1.1 christos encoded[len-3] = '\0';
401 1.1 christos blen = uudecode(encoded, blob, sizeof(blob));
402 1.1 christos if (blen < 0) {
403 1.1 christos fprintf(stderr, "uudecode failed.\n");
404 1.1 christos exit(1);
405 1.1 christos }
406 1.1 christos k = private ?
407 1.1 christos do_convert_private_ssh2_from_blob(blob, blen) :
408 1.1 christos key_from_blob(blob, blen);
409 1.1 christos if (k == NULL) {
410 1.1 christos fprintf(stderr, "decode blob failed.\n");
411 1.1 christos exit(1);
412 1.1 christos }
413 1.1 christos ok = private ?
414 1.1 christos (k->type == KEY_DSA ?
415 1.1 christos PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) :
416 1.1 christos PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) :
417 1.1 christos key_write(k, stdout);
418 1.1 christos if (!ok) {
419 1.1 christos fprintf(stderr, "key write failed\n");
420 1.1 christos exit(1);
421 1.1 christos }
422 1.1 christos key_free(k);
423 1.1 christos if (!private)
424 1.1 christos fprintf(stdout, "\n");
425 1.1 christos fclose(fp);
426 1.1 christos exit(0);
427 1.1 christos }
428 1.1 christos
429 1.1 christos static void
430 1.1 christos do_print_public(struct passwd *pw)
431 1.1 christos {
432 1.1 christos Key *prv;
433 1.1 christos struct stat st;
434 1.1 christos
435 1.1 christos if (!have_identity)
436 1.1 christos ask_filename(pw, "Enter file in which the key is");
437 1.1 christos if (stat(identity_file, &st) < 0) {
438 1.1 christos perror(identity_file);
439 1.1 christos exit(1);
440 1.1 christos }
441 1.1 christos prv = load_identity(identity_file);
442 1.1 christos if (prv == NULL) {
443 1.1 christos fprintf(stderr, "load failed\n");
444 1.1 christos exit(1);
445 1.1 christos }
446 1.1 christos if (!key_write(prv, stdout))
447 1.1 christos fprintf(stderr, "key_write failed");
448 1.1 christos key_free(prv);
449 1.1 christos fprintf(stdout, "\n");
450 1.1 christos exit(0);
451 1.1 christos }
452 1.1 christos
453 1.1 christos #ifdef SMARTCARD
454 1.1 christos static void
455 1.1 christos do_upload(struct passwd *pw, const char *sc_reader_id)
456 1.1 christos {
457 1.1 christos Key *prv = NULL;
458 1.1 christos struct stat st;
459 1.1 christos int ret;
460 1.1 christos
461 1.1 christos if (!have_identity)
462 1.1 christos ask_filename(pw, "Enter file in which the key is");
463 1.1 christos if (stat(identity_file, &st) < 0) {
464 1.1 christos perror(identity_file);
465 1.1 christos exit(1);
466 1.1 christos }
467 1.1 christos prv = load_identity(identity_file);
468 1.1 christos if (prv == NULL) {
469 1.1 christos error("load failed");
470 1.1 christos exit(1);
471 1.1 christos }
472 1.1 christos ret = sc_put_key(prv, sc_reader_id);
473 1.1 christos key_free(prv);
474 1.1 christos if (ret < 0)
475 1.1 christos exit(1);
476 1.1 christos logit("loading key done");
477 1.1 christos exit(0);
478 1.1 christos }
479 1.1 christos
480 1.1 christos static void
481 1.1 christos do_download(struct passwd *pw, const char *sc_reader_id)
482 1.1 christos {
483 1.1 christos Key **keys = NULL;
484 1.1 christos int i;
485 1.1 christos
486 1.1 christos keys = sc_get_keys(sc_reader_id, NULL);
487 1.1 christos if (keys == NULL)
488 1.1 christos fatal("cannot read public key from smartcard");
489 1.1 christos for (i = 0; keys[i]; i++) {
490 1.1 christos key_write(keys[i], stdout);
491 1.1 christos key_free(keys[i]);
492 1.1 christos fprintf(stdout, "\n");
493 1.1 christos }
494 1.1 christos xfree(keys);
495 1.1 christos exit(0);
496 1.1 christos }
497 1.1 christos #endif /* SMARTCARD */
498 1.1 christos
499 1.1 christos static void
500 1.1 christos do_fingerprint(struct passwd *pw)
501 1.1 christos {
502 1.1 christos FILE *f;
503 1.1 christos Key *public;
504 1.1 christos char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra;
505 1.1 christos int i, skip = 0, num = 0, invalid = 1;
506 1.1 christos enum fp_rep rep;
507 1.1 christos enum fp_type fptype;
508 1.1 christos struct stat st;
509 1.1 christos
510 1.1 christos fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
511 1.1 christos rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
512 1.1 christos
513 1.1 christos if (!have_identity)
514 1.1 christos ask_filename(pw, "Enter file in which the key is");
515 1.1 christos if (stat(identity_file, &st) < 0) {
516 1.1 christos perror(identity_file);
517 1.1 christos exit(1);
518 1.1 christos }
519 1.1 christos public = key_load_public(identity_file, &comment);
520 1.1 christos if (public != NULL) {
521 1.1 christos fp = key_fingerprint(public, fptype, rep);
522 1.1 christos ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART);
523 1.1 christos printf("%u %s %s (%s)\n", key_size(public), fp, comment,
524 1.1 christos key_type(public));
525 1.1 christos if (log_level >= SYSLOG_LEVEL_VERBOSE)
526 1.1 christos printf("%s\n", ra);
527 1.1 christos key_free(public);
528 1.1 christos xfree(comment);
529 1.1 christos xfree(ra);
530 1.1 christos xfree(fp);
531 1.1 christos exit(0);
532 1.1 christos }
533 1.1 christos if (comment) {
534 1.1 christos xfree(comment);
535 1.1 christos comment = NULL;
536 1.1 christos }
537 1.1 christos
538 1.1 christos f = fopen(identity_file, "r");
539 1.1 christos if (f != NULL) {
540 1.1 christos while (fgets(line, sizeof(line), f)) {
541 1.1 christos if ((cp = strchr(line, '\n')) == NULL) {
542 1.1 christos error("line %d too long: %.40s...",
543 1.1 christos num + 1, line);
544 1.1 christos skip = 1;
545 1.1 christos continue;
546 1.1 christos }
547 1.1 christos num++;
548 1.1 christos if (skip) {
549 1.1 christos skip = 0;
550 1.1 christos continue;
551 1.1 christos }
552 1.1 christos *cp = '\0';
553 1.1 christos
554 1.1 christos /* Skip leading whitespace, empty and comment lines. */
555 1.1 christos for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
556 1.1 christos ;
557 1.1 christos if (!*cp || *cp == '\n' || *cp == '#')
558 1.1 christos continue;
559 1.1 christos i = strtol(cp, &ep, 10);
560 1.1 christos if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
561 1.1 christos int quoted = 0;
562 1.1 christos comment = cp;
563 1.1 christos for (; *cp && (quoted || (*cp != ' ' &&
564 1.1 christos *cp != '\t')); cp++) {
565 1.1 christos if (*cp == '\\' && cp[1] == '"')
566 1.1 christos cp++; /* Skip both */
567 1.1 christos else if (*cp == '"')
568 1.1 christos quoted = !quoted;
569 1.1 christos }
570 1.1 christos if (!*cp)
571 1.1 christos continue;
572 1.1 christos *cp++ = '\0';
573 1.1 christos }
574 1.1 christos ep = cp;
575 1.1 christos public = key_new(KEY_RSA1);
576 1.1 christos if (key_read(public, &cp) != 1) {
577 1.1 christos cp = ep;
578 1.1 christos key_free(public);
579 1.1 christos public = key_new(KEY_UNSPEC);
580 1.1 christos if (key_read(public, &cp) != 1) {
581 1.1 christos key_free(public);
582 1.1 christos continue;
583 1.1 christos }
584 1.1 christos }
585 1.1 christos comment = *cp ? cp : comment;
586 1.1 christos fp = key_fingerprint(public, fptype, rep);
587 1.1 christos ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART);
588 1.1 christos printf("%u %s %s (%s)\n", key_size(public), fp,
589 1.1 christos comment ? comment : "no comment", key_type(public));
590 1.1 christos if (log_level >= SYSLOG_LEVEL_VERBOSE)
591 1.1 christos printf("%s\n", ra);
592 1.1 christos xfree(ra);
593 1.1 christos xfree(fp);
594 1.1 christos key_free(public);
595 1.1 christos invalid = 0;
596 1.1 christos }
597 1.1 christos fclose(f);
598 1.1 christos }
599 1.1 christos if (invalid) {
600 1.1 christos printf("%s is not a public key file.\n", identity_file);
601 1.1 christos exit(1);
602 1.1 christos }
603 1.1 christos exit(0);
604 1.1 christos }
605 1.1 christos
606 1.1 christos static void
607 1.1 christos print_host(FILE *f, const char *name, Key *public, int hash)
608 1.1 christos {
609 1.1 christos if (print_fingerprint) {
610 1.1 christos enum fp_rep rep;
611 1.1 christos enum fp_type fptype;
612 1.1 christos char *fp, *ra;
613 1.1 christos
614 1.1 christos fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
615 1.1 christos rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
616 1.1 christos fp = key_fingerprint(public, fptype, rep);
617 1.1 christos ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART);
618 1.1 christos printf("%u %s %s (%s)\n", key_size(public), fp, name,
619 1.1 christos key_type(public));
620 1.1 christos if (log_level >= SYSLOG_LEVEL_VERBOSE)
621 1.1 christos printf("%s\n", ra);
622 1.1 christos xfree(ra);
623 1.1 christos xfree(fp);
624 1.1 christos } else {
625 1.1 christos if (hash && (name = host_hash(name, NULL, 0)) == NULL)
626 1.1 christos fatal("hash_host failed");
627 1.1 christos fprintf(f, "%s ", name);
628 1.1 christos if (!key_write(public, f))
629 1.1 christos fatal("key_write failed");
630 1.1 christos fprintf(f, "\n");
631 1.1 christos }
632 1.1 christos }
633 1.1 christos
634 1.1 christos static void
635 1.1 christos do_known_hosts(struct passwd *pw, const char *name)
636 1.1 christos {
637 1.1 christos FILE *in, *out = stdout;
638 1.1 christos Key *public;
639 1.1 christos char *cp, *cp2, *kp, *kp2;
640 1.1 christos char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN];
641 1.1 christos int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0;
642 1.1 christos
643 1.1 christos if (!have_identity) {
644 1.1 christos cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
645 1.1 christos if (strlcpy(identity_file, cp, sizeof(identity_file)) >=
646 1.1 christos sizeof(identity_file))
647 1.1 christos fatal("Specified known hosts path too long");
648 1.1 christos xfree(cp);
649 1.1 christos have_identity = 1;
650 1.1 christos }
651 1.1 christos if ((in = fopen(identity_file, "r")) == NULL)
652 1.1 christos fatal("fopen: %s", strerror(errno));
653 1.1 christos
654 1.1 christos /*
655 1.1 christos * Find hosts goes to stdout, hash and deletions happen in-place
656 1.1 christos * A corner case is ssh-keygen -HF foo, which should go to stdout
657 1.1 christos */
658 1.1 christos if (!find_host && (hash_hosts || delete_host)) {
659 1.1 christos if (strlcpy(tmp, identity_file, sizeof(tmp)) >= sizeof(tmp) ||
660 1.1 christos strlcat(tmp, ".XXXXXXXXXX", sizeof(tmp)) >= sizeof(tmp) ||
661 1.1 christos strlcpy(old, identity_file, sizeof(old)) >= sizeof(old) ||
662 1.1 christos strlcat(old, ".old", sizeof(old)) >= sizeof(old))
663 1.1 christos fatal("known_hosts path too long");
664 1.1 christos umask(077);
665 1.1 christos if ((c = mkstemp(tmp)) == -1)
666 1.1 christos fatal("mkstemp: %s", strerror(errno));
667 1.1 christos if ((out = fdopen(c, "w")) == NULL) {
668 1.1 christos c = errno;
669 1.1 christos unlink(tmp);
670 1.1 christos fatal("fdopen: %s", strerror(c));
671 1.1 christos }
672 1.1 christos inplace = 1;
673 1.1 christos }
674 1.1 christos
675 1.1 christos while (fgets(line, sizeof(line), in)) {
676 1.1 christos if ((cp = strchr(line, '\n')) == NULL) {
677 1.1 christos error("line %d too long: %.40s...", num + 1, line);
678 1.1 christos skip = 1;
679 1.1 christos invalid = 1;
680 1.1 christos continue;
681 1.1 christos }
682 1.1 christos num++;
683 1.1 christos if (skip) {
684 1.1 christos skip = 0;
685 1.1 christos continue;
686 1.1 christos }
687 1.1 christos *cp = '\0';
688 1.1 christos
689 1.1 christos /* Skip leading whitespace, empty and comment lines. */
690 1.1 christos for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
691 1.1 christos ;
692 1.1 christos if (!*cp || *cp == '\n' || *cp == '#') {
693 1.1 christos if (inplace)
694 1.1 christos fprintf(out, "%s\n", cp);
695 1.1 christos continue;
696 1.1 christos }
697 1.1 christos /* Find the end of the host name portion. */
698 1.1 christos for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++)
699 1.1 christos ;
700 1.1 christos if (*kp == '\0' || *(kp + 1) == '\0') {
701 1.1 christos error("line %d missing key: %.40s...",
702 1.1 christos num, line);
703 1.1 christos invalid = 1;
704 1.1 christos continue;
705 1.1 christos }
706 1.1 christos *kp++ = '\0';
707 1.1 christos kp2 = kp;
708 1.1 christos
709 1.1 christos public = key_new(KEY_RSA1);
710 1.1 christos if (key_read(public, &kp) != 1) {
711 1.1 christos kp = kp2;
712 1.1 christos key_free(public);
713 1.1 christos public = key_new(KEY_UNSPEC);
714 1.1 christos if (key_read(public, &kp) != 1) {
715 1.1 christos error("line %d invalid key: %.40s...",
716 1.1 christos num, line);
717 1.1 christos key_free(public);
718 1.1 christos invalid = 1;
719 1.1 christos continue;
720 1.1 christos }
721 1.1 christos }
722 1.1 christos
723 1.1 christos if (*cp == HASH_DELIM) {
724 1.1 christos if (find_host || delete_host) {
725 1.1 christos cp2 = host_hash(name, cp, strlen(cp));
726 1.1 christos if (cp2 == NULL) {
727 1.1 christos error("line %d: invalid hashed "
728 1.1 christos "name: %.64s...", num, line);
729 1.1 christos invalid = 1;
730 1.1 christos continue;
731 1.1 christos }
732 1.1 christos c = (strcmp(cp2, cp) == 0);
733 1.1 christos if (find_host && c) {
734 1.1 christos printf("# Host %s found: "
735 1.1 christos "line %d type %s\n", name,
736 1.1 christos num, key_type(public));
737 1.1 christos print_host(out, cp, public, 0);
738 1.1 christos }
739 1.1 christos if (delete_host && !c)
740 1.1 christos print_host(out, cp, public, 0);
741 1.1 christos } else if (hash_hosts)
742 1.1 christos print_host(out, cp, public, 0);
743 1.1 christos } else {
744 1.1 christos if (find_host || delete_host) {
745 1.1 christos c = (match_hostname(name, cp,
746 1.1 christos strlen(cp)) == 1);
747 1.1 christos if (find_host && c) {
748 1.1 christos printf("# Host %s found: "
749 1.1 christos "line %d type %s\n", name,
750 1.1 christos num, key_type(public));
751 1.1 christos print_host(out, name, public,
752 1.1 christos hash_hosts);
753 1.1 christos }
754 1.1 christos if (delete_host && !c)
755 1.1 christos print_host(out, cp, public, 0);
756 1.1 christos } else if (hash_hosts) {
757 1.1 christos for (cp2 = strsep(&cp, ",");
758 1.1 christos cp2 != NULL && *cp2 != '\0';
759 1.1 christos cp2 = strsep(&cp, ",")) {
760 1.1 christos if (strcspn(cp2, "*?!") != strlen(cp2))
761 1.1 christos fprintf(stderr, "Warning: "
762 1.1 christos "ignoring host name with "
763 1.1 christos "metacharacters: %.64s\n",
764 1.1 christos cp2);
765 1.1 christos else
766 1.1 christos print_host(out, cp2, public, 1);
767 1.1 christos }
768 1.1 christos has_unhashed = 1;
769 1.1 christos }
770 1.1 christos }
771 1.1 christos key_free(public);
772 1.1 christos }
773 1.1 christos fclose(in);
774 1.1 christos
775 1.1 christos if (invalid) {
776 1.1 christos fprintf(stderr, "%s is not a valid known_hosts file.\n",
777 1.1 christos identity_file);
778 1.1 christos if (inplace) {
779 1.1 christos fprintf(stderr, "Not replacing existing known_hosts "
780 1.1 christos "file because of errors\n");
781 1.1 christos fclose(out);
782 1.1 christos unlink(tmp);
783 1.1 christos }
784 1.1 christos exit(1);
785 1.1 christos }
786 1.1 christos
787 1.1 christos if (inplace) {
788 1.1 christos fclose(out);
789 1.1 christos
790 1.1 christos /* Backup existing file */
791 1.1 christos if (unlink(old) == -1 && errno != ENOENT)
792 1.1 christos fatal("unlink %.100s: %s", old, strerror(errno));
793 1.1 christos if (link(identity_file, old) == -1)
794 1.1 christos fatal("link %.100s to %.100s: %s", identity_file, old,
795 1.1 christos strerror(errno));
796 1.1 christos /* Move new one into place */
797 1.1 christos if (rename(tmp, identity_file) == -1) {
798 1.1 christos error("rename\"%s\" to \"%s\": %s", tmp, identity_file,
799 1.1 christos strerror(errno));
800 1.1 christos unlink(tmp);
801 1.1 christos unlink(old);
802 1.1 christos exit(1);
803 1.1 christos }
804 1.1 christos
805 1.1 christos fprintf(stderr, "%s updated.\n", identity_file);
806 1.1 christos fprintf(stderr, "Original contents retained as %s\n", old);
807 1.1 christos if (has_unhashed) {
808 1.1 christos fprintf(stderr, "WARNING: %s contains unhashed "
809 1.1 christos "entries\n", old);
810 1.1 christos fprintf(stderr, "Delete this file to ensure privacy "
811 1.1 christos "of hostnames\n");
812 1.1 christos }
813 1.1 christos }
814 1.1 christos
815 1.1 christos exit(0);
816 1.1 christos }
817 1.1 christos
818 1.1 christos /*
819 1.1 christos * Perform changing a passphrase. The argument is the passwd structure
820 1.1 christos * for the current user.
821 1.1 christos */
822 1.1 christos static void
823 1.1 christos do_change_passphrase(struct passwd *pw)
824 1.1 christos {
825 1.1 christos char *comment;
826 1.1 christos char *old_passphrase, *passphrase1, *passphrase2;
827 1.1 christos struct stat st;
828 1.1 christos Key *private;
829 1.1 christos
830 1.1 christos if (!have_identity)
831 1.1 christos ask_filename(pw, "Enter file in which the key is");
832 1.1 christos if (stat(identity_file, &st) < 0) {
833 1.1 christos perror(identity_file);
834 1.1 christos exit(1);
835 1.1 christos }
836 1.1 christos /* Try to load the file with empty passphrase. */
837 1.1 christos private = key_load_private(identity_file, "", &comment);
838 1.1 christos if (private == NULL) {
839 1.1 christos if (identity_passphrase)
840 1.1 christos old_passphrase = xstrdup(identity_passphrase);
841 1.1 christos else
842 1.1 christos old_passphrase =
843 1.1 christos read_passphrase("Enter old passphrase: ",
844 1.1 christos RP_ALLOW_STDIN);
845 1.1 christos private = key_load_private(identity_file, old_passphrase,
846 1.1 christos &comment);
847 1.1 christos memset(old_passphrase, 0, strlen(old_passphrase));
848 1.1 christos xfree(old_passphrase);
849 1.1 christos if (private == NULL) {
850 1.1 christos printf("Bad passphrase.\n");
851 1.1 christos exit(1);
852 1.1 christos }
853 1.1 christos }
854 1.1 christos printf("Key has comment '%s'\n", comment);
855 1.1 christos
856 1.1 christos /* Ask the new passphrase (twice). */
857 1.1 christos if (identity_new_passphrase) {
858 1.1 christos passphrase1 = xstrdup(identity_new_passphrase);
859 1.1 christos passphrase2 = NULL;
860 1.1 christos } else {
861 1.1 christos passphrase1 =
862 1.1 christos read_passphrase("Enter new passphrase (empty for no "
863 1.1 christos "passphrase): ", RP_ALLOW_STDIN);
864 1.1 christos passphrase2 = read_passphrase("Enter same passphrase again: ",
865 1.1 christos RP_ALLOW_STDIN);
866 1.1 christos
867 1.1 christos /* Verify that they are the same. */
868 1.1 christos if (strcmp(passphrase1, passphrase2) != 0) {
869 1.1 christos memset(passphrase1, 0, strlen(passphrase1));
870 1.1 christos memset(passphrase2, 0, strlen(passphrase2));
871 1.1 christos xfree(passphrase1);
872 1.1 christos xfree(passphrase2);
873 1.1 christos printf("Pass phrases do not match. Try again.\n");
874 1.1 christos exit(1);
875 1.1 christos }
876 1.1 christos /* Destroy the other copy. */
877 1.1 christos memset(passphrase2, 0, strlen(passphrase2));
878 1.1 christos xfree(passphrase2);
879 1.1 christos }
880 1.1 christos
881 1.1 christos /* Save the file using the new passphrase. */
882 1.1 christos if (!key_save_private(private, identity_file, passphrase1, comment)) {
883 1.1 christos printf("Saving the key failed: %s.\n", identity_file);
884 1.1 christos memset(passphrase1, 0, strlen(passphrase1));
885 1.1 christos xfree(passphrase1);
886 1.1 christos key_free(private);
887 1.1 christos xfree(comment);
888 1.1 christos exit(1);
889 1.1 christos }
890 1.1 christos /* Destroy the passphrase and the copy of the key in memory. */
891 1.1 christos memset(passphrase1, 0, strlen(passphrase1));
892 1.1 christos xfree(passphrase1);
893 1.1 christos key_free(private); /* Destroys contents */
894 1.1 christos xfree(comment);
895 1.1 christos
896 1.1 christos printf("Your identification has been saved with the new passphrase.\n");
897 1.1 christos exit(0);
898 1.1 christos }
899 1.1 christos
900 1.1 christos /*
901 1.1 christos * Print the SSHFP RR.
902 1.1 christos */
903 1.1 christos static int
904 1.1 christos do_print_resource_record(struct passwd *pw, char *fname, char *hname)
905 1.1 christos {
906 1.1 christos Key *public;
907 1.1 christos char *comment = NULL;
908 1.1 christos struct stat st;
909 1.1 christos
910 1.1 christos if (fname == NULL)
911 1.1 christos ask_filename(pw, "Enter file in which the key is");
912 1.1 christos if (stat(fname, &st) < 0) {
913 1.1 christos if (errno == ENOENT)
914 1.1 christos return 0;
915 1.1 christos perror(fname);
916 1.1 christos exit(1);
917 1.1 christos }
918 1.1 christos public = key_load_public(fname, &comment);
919 1.1 christos if (public != NULL) {
920 1.1 christos export_dns_rr(hname, public, stdout, print_generic);
921 1.1 christos key_free(public);
922 1.1 christos xfree(comment);
923 1.1 christos return 1;
924 1.1 christos }
925 1.1 christos if (comment)
926 1.1 christos xfree(comment);
927 1.1 christos
928 1.1 christos printf("failed to read v2 public key from %s.\n", fname);
929 1.1 christos exit(1);
930 1.1 christos }
931 1.1 christos
932 1.1 christos /*
933 1.1 christos * Change the comment of a private key file.
934 1.1 christos */
935 1.1 christos static void
936 1.1 christos do_change_comment(struct passwd *pw)
937 1.1 christos {
938 1.1 christos char new_comment[1024], *comment, *passphrase;
939 1.1 christos Key *private;
940 1.1 christos Key *public;
941 1.1 christos struct stat st;
942 1.1 christos FILE *f;
943 1.1 christos int fd;
944 1.1 christos
945 1.1 christos if (!have_identity)
946 1.1 christos ask_filename(pw, "Enter file in which the key is");
947 1.1 christos if (stat(identity_file, &st) < 0) {
948 1.1 christos perror(identity_file);
949 1.1 christos exit(1);
950 1.1 christos }
951 1.1 christos private = key_load_private(identity_file, "", &comment);
952 1.1 christos if (private == NULL) {
953 1.1 christos if (identity_passphrase)
954 1.1 christos passphrase = xstrdup(identity_passphrase);
955 1.1 christos else if (identity_new_passphrase)
956 1.1 christos passphrase = xstrdup(identity_new_passphrase);
957 1.1 christos else
958 1.1 christos passphrase = read_passphrase("Enter passphrase: ",
959 1.1 christos RP_ALLOW_STDIN);
960 1.1 christos /* Try to load using the passphrase. */
961 1.1 christos private = key_load_private(identity_file, passphrase, &comment);
962 1.1 christos if (private == NULL) {
963 1.1 christos memset(passphrase, 0, strlen(passphrase));
964 1.1 christos xfree(passphrase);
965 1.1 christos printf("Bad passphrase.\n");
966 1.1 christos exit(1);
967 1.1 christos }
968 1.1 christos } else {
969 1.1 christos passphrase = xstrdup("");
970 1.1 christos }
971 1.1 christos if (private->type != KEY_RSA1) {
972 1.1 christos fprintf(stderr, "Comments are only supported for RSA1 keys.\n");
973 1.1 christos key_free(private);
974 1.1 christos exit(1);
975 1.1 christos }
976 1.1 christos printf("Key now has comment '%s'\n", comment);
977 1.1 christos
978 1.1 christos if (identity_comment) {
979 1.1 christos strlcpy(new_comment, identity_comment, sizeof(new_comment));
980 1.1 christos } else {
981 1.1 christos printf("Enter new comment: ");
982 1.1 christos fflush(stdout);
983 1.1 christos if (!fgets(new_comment, sizeof(new_comment), stdin)) {
984 1.1 christos memset(passphrase, 0, strlen(passphrase));
985 1.1 christos key_free(private);
986 1.1 christos exit(1);
987 1.1 christos }
988 1.1 christos new_comment[strcspn(new_comment, "\n")] = '\0';
989 1.1 christos }
990 1.1 christos
991 1.1 christos /* Save the file using the new passphrase. */
992 1.1 christos if (!key_save_private(private, identity_file, passphrase, new_comment)) {
993 1.1 christos printf("Saving the key failed: %s.\n", identity_file);
994 1.1 christos memset(passphrase, 0, strlen(passphrase));
995 1.1 christos xfree(passphrase);
996 1.1 christos key_free(private);
997 1.1 christos xfree(comment);
998 1.1 christos exit(1);
999 1.1 christos }
1000 1.1 christos memset(passphrase, 0, strlen(passphrase));
1001 1.1 christos xfree(passphrase);
1002 1.1 christos public = key_from_private(private);
1003 1.1 christos key_free(private);
1004 1.1 christos
1005 1.1 christos strlcat(identity_file, ".pub", sizeof(identity_file));
1006 1.1 christos fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1007 1.1 christos if (fd == -1) {
1008 1.1 christos printf("Could not save your public key in %s\n", identity_file);
1009 1.1 christos exit(1);
1010 1.1 christos }
1011 1.1 christos f = fdopen(fd, "w");
1012 1.1 christos if (f == NULL) {
1013 1.1 christos printf("fdopen %s failed\n", identity_file);
1014 1.1 christos exit(1);
1015 1.1 christos }
1016 1.1 christos if (!key_write(public, f))
1017 1.1 christos fprintf(stderr, "write key failed\n");
1018 1.1 christos key_free(public);
1019 1.1 christos fprintf(f, " %s\n", new_comment);
1020 1.1 christos fclose(f);
1021 1.1 christos
1022 1.1 christos xfree(comment);
1023 1.1 christos
1024 1.1 christos printf("The comment in your key file has been changed.\n");
1025 1.1 christos exit(0);
1026 1.1 christos }
1027 1.1 christos
1028 1.1 christos static void
1029 1.1 christos usage(void)
1030 1.1 christos {
1031 1.1 christos fprintf(stderr, "usage: %s [options]\n", __progname);
1032 1.1 christos fprintf(stderr, "Options:\n");
1033 1.1 christos fprintf(stderr, " -a trials Number of trials for screening DH-GEX moduli.\n");
1034 1.1 christos fprintf(stderr, " -B Show bubblebabble digest of key file.\n");
1035 1.1 christos fprintf(stderr, " -b bits Number of bits in the key to create.\n");
1036 1.1 christos fprintf(stderr, " -C comment Provide new comment.\n");
1037 1.1 christos fprintf(stderr, " -c Change comment in private and public key files.\n");
1038 1.1 christos #ifdef SMARTCARD
1039 1.1 christos fprintf(stderr, " -D reader Download public key from smartcard.\n");
1040 1.1 christos #endif /* SMARTCARD */
1041 1.1 christos fprintf(stderr, " -e Convert OpenSSH to RFC 4716 key file.\n");
1042 1.1 christos fprintf(stderr, " -F hostname Find hostname in known hosts file.\n");
1043 1.1 christos fprintf(stderr, " -f filename Filename of the key file.\n");
1044 1.1 christos fprintf(stderr, " -G file Generate candidates for DH-GEX moduli.\n");
1045 1.1 christos fprintf(stderr, " -g Use generic DNS resource record format.\n");
1046 1.1 christos fprintf(stderr, " -H Hash names in known_hosts file.\n");
1047 1.1 christos fprintf(stderr, " -i Convert RFC 4716 to OpenSSH key file.\n");
1048 1.1 christos fprintf(stderr, " -l Show fingerprint of key file.\n");
1049 1.1 christos fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n");
1050 1.1 christos fprintf(stderr, " -N phrase Provide new passphrase.\n");
1051 1.1 christos fprintf(stderr, " -P phrase Provide old passphrase.\n");
1052 1.1 christos fprintf(stderr, " -p Change passphrase of private key file.\n");
1053 1.1 christos fprintf(stderr, " -q Quiet.\n");
1054 1.1 christos fprintf(stderr, " -R hostname Remove host from known_hosts file.\n");
1055 1.1 christos fprintf(stderr, " -r hostname Print DNS resource record.\n");
1056 1.1 christos fprintf(stderr, " -S start Start point (hex) for generating DH-GEX moduli.\n");
1057 1.1 christos fprintf(stderr, " -T file Screen candidates for DH-GEX moduli.\n");
1058 1.1 christos fprintf(stderr, " -t type Specify type of key to create.\n");
1059 1.1 christos #ifdef SMARTCARD
1060 1.1 christos fprintf(stderr, " -U reader Upload private key to smartcard.\n");
1061 1.1 christos #endif /* SMARTCARD */
1062 1.1 christos fprintf(stderr, " -v Verbose.\n");
1063 1.1 christos fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n");
1064 1.1 christos fprintf(stderr, " -y Read private key file and print public key.\n");
1065 1.1 christos
1066 1.1 christos exit(1);
1067 1.1 christos }
1068 1.1 christos
1069 1.1 christos /*
1070 1.1 christos * Main program for key management.
1071 1.1 christos */
1072 1.1 christos int
1073 1.1 christos main(int argc, char **argv)
1074 1.1 christos {
1075 1.1 christos char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2;
1076 1.1 christos char out_file[MAXPATHLEN], *reader_id = NULL;
1077 1.1 christos char *rr_hostname = NULL;
1078 1.1 christos Key *private, *public;
1079 1.1 christos struct passwd *pw;
1080 1.1 christos struct stat st;
1081 1.1 christos int opt, type, fd, download = 0;
1082 1.1 christos u_int32_t memory = 0, generator_wanted = 0, trials = 100;
1083 1.1 christos int do_gen_candidates = 0, do_screen_candidates = 0;
1084 1.1 christos BIGNUM *start = NULL;
1085 1.1 christos FILE *f;
1086 1.1 christos const char *errstr;
1087 1.1 christos
1088 1.1 christos extern int optind;
1089 1.1 christos extern char *optarg;
1090 1.1 christos
1091 1.1 christos /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1092 1.1 christos sanitise_stdfd();
1093 1.1 christos
1094 1.1 christos SSLeay_add_all_algorithms();
1095 1.1 christos log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
1096 1.1 christos
1097 1.1 christos /* we need this for the home * directory. */
1098 1.1 christos pw = getpwuid(getuid());
1099 1.1 christos if (!pw) {
1100 1.1 christos printf("You don't exist, go away!\n");
1101 1.1 christos exit(1);
1102 1.1 christos }
1103 1.1 christos if (gethostname(hostname, sizeof(hostname)) < 0) {
1104 1.1 christos perror("gethostname");
1105 1.1 christos exit(1);
1106 1.1 christos }
1107 1.1 christos
1108 1.1 christos while ((opt = getopt(argc, argv,
1109 1.1 christos "degiqpclBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) {
1110 1.1 christos switch (opt) {
1111 1.1 christos case 'b':
1112 1.1 christos bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr);
1113 1.1 christos if (errstr)
1114 1.1 christos fatal("Bits has bad value %s (%s)",
1115 1.1 christos optarg, errstr);
1116 1.1 christos break;
1117 1.1 christos case 'F':
1118 1.1 christos find_host = 1;
1119 1.1 christos rr_hostname = optarg;
1120 1.1 christos break;
1121 1.1 christos case 'H':
1122 1.1 christos hash_hosts = 1;
1123 1.1 christos break;
1124 1.1 christos case 'R':
1125 1.1 christos delete_host = 1;
1126 1.1 christos rr_hostname = optarg;
1127 1.1 christos break;
1128 1.1 christos case 'l':
1129 1.1 christos print_fingerprint = 1;
1130 1.1 christos break;
1131 1.1 christos case 'B':
1132 1.1 christos print_bubblebabble = 1;
1133 1.1 christos break;
1134 1.1 christos case 'p':
1135 1.1 christos change_passphrase = 1;
1136 1.1 christos break;
1137 1.1 christos case 'c':
1138 1.1 christos change_comment = 1;
1139 1.1 christos break;
1140 1.1 christos case 'f':
1141 1.1 christos if (strlcpy(identity_file, optarg, sizeof(identity_file)) >=
1142 1.1 christos sizeof(identity_file))
1143 1.1 christos fatal("Identity filename too long");
1144 1.1 christos have_identity = 1;
1145 1.1 christos break;
1146 1.1 christos case 'g':
1147 1.1 christos print_generic = 1;
1148 1.1 christos break;
1149 1.1 christos case 'P':
1150 1.1 christos identity_passphrase = optarg;
1151 1.1 christos break;
1152 1.1 christos case 'N':
1153 1.1 christos identity_new_passphrase = optarg;
1154 1.1 christos break;
1155 1.1 christos case 'C':
1156 1.1 christos identity_comment = optarg;
1157 1.1 christos break;
1158 1.1 christos case 'q':
1159 1.1 christos quiet = 1;
1160 1.1 christos break;
1161 1.1 christos case 'e':
1162 1.1 christos case 'x':
1163 1.1 christos /* export key */
1164 1.1 christos convert_to_ssh2 = 1;
1165 1.1 christos break;
1166 1.1 christos case 'i':
1167 1.1 christos case 'X':
1168 1.1 christos /* import key */
1169 1.1 christos convert_from_ssh2 = 1;
1170 1.1 christos break;
1171 1.1 christos case 'y':
1172 1.1 christos print_public = 1;
1173 1.1 christos break;
1174 1.1 christos case 'd':
1175 1.1 christos key_type_name = "dsa";
1176 1.1 christos break;
1177 1.1 christos case 't':
1178 1.1 christos key_type_name = optarg;
1179 1.1 christos break;
1180 1.1 christos case 'D':
1181 1.1 christos download = 1;
1182 1.1 christos /*FALLTHROUGH*/
1183 1.1 christos case 'U':
1184 1.1 christos reader_id = optarg;
1185 1.1 christos break;
1186 1.1 christos case 'v':
1187 1.1 christos if (log_level == SYSLOG_LEVEL_INFO)
1188 1.1 christos log_level = SYSLOG_LEVEL_DEBUG1;
1189 1.1 christos else {
1190 1.1 christos if (log_level >= SYSLOG_LEVEL_DEBUG1 &&
1191 1.1 christos log_level < SYSLOG_LEVEL_DEBUG3)
1192 1.1 christos log_level++;
1193 1.1 christos }
1194 1.1 christos break;
1195 1.1 christos case 'r':
1196 1.1 christos rr_hostname = optarg;
1197 1.1 christos break;
1198 1.1 christos case 'W':
1199 1.1 christos generator_wanted = (u_int32_t)strtonum(optarg, 1,
1200 1.1 christos UINT_MAX, &errstr);
1201 1.1 christos if (errstr)
1202 1.1 christos fatal("Desired generator has bad value: %s (%s)",
1203 1.1 christos optarg, errstr);
1204 1.1 christos break;
1205 1.1 christos case 'a':
1206 1.1 christos trials = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr);
1207 1.1 christos if (errstr)
1208 1.1 christos fatal("Invalid number of trials: %s (%s)",
1209 1.1 christos optarg, errstr);
1210 1.1 christos break;
1211 1.1 christos case 'M':
1212 1.1 christos memory = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr);
1213 1.1 christos if (errstr) {
1214 1.1 christos fatal("Memory limit is %s: %s", errstr, optarg);
1215 1.1 christos }
1216 1.1 christos break;
1217 1.1 christos case 'G':
1218 1.1 christos do_gen_candidates = 1;
1219 1.1 christos if (strlcpy(out_file, optarg, sizeof(out_file)) >=
1220 1.1 christos sizeof(out_file))
1221 1.1 christos fatal("Output filename too long");
1222 1.1 christos break;
1223 1.1 christos case 'T':
1224 1.1 christos do_screen_candidates = 1;
1225 1.1 christos if (strlcpy(out_file, optarg, sizeof(out_file)) >=
1226 1.1 christos sizeof(out_file))
1227 1.1 christos fatal("Output filename too long");
1228 1.1 christos break;
1229 1.1 christos case 'S':
1230 1.1 christos /* XXX - also compare length against bits */
1231 1.1 christos if (BN_hex2bn(&start, optarg) == 0)
1232 1.1 christos fatal("Invalid start point.");
1233 1.1 christos break;
1234 1.1 christos case '?':
1235 1.1 christos default:
1236 1.1 christos usage();
1237 1.1 christos }
1238 1.1 christos }
1239 1.1 christos
1240 1.1 christos /* reinit */
1241 1.1 christos log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1);
1242 1.1 christos
1243 1.1 christos if (optind < argc) {
1244 1.1 christos printf("Too many arguments.\n");
1245 1.1 christos usage();
1246 1.1 christos }
1247 1.1 christos if (change_passphrase && change_comment) {
1248 1.1 christos printf("Can only have one of -p and -c.\n");
1249 1.1 christos usage();
1250 1.1 christos }
1251 1.1 christos if (print_fingerprint && (delete_host || hash_hosts)) {
1252 1.1 christos printf("Cannot use -l with -D or -R.\n");
1253 1.1 christos usage();
1254 1.1 christos }
1255 1.1 christos if (delete_host || hash_hosts || find_host)
1256 1.1 christos do_known_hosts(pw, rr_hostname);
1257 1.1 christos if (print_fingerprint || print_bubblebabble)
1258 1.1 christos do_fingerprint(pw);
1259 1.1 christos if (change_passphrase)
1260 1.1 christos do_change_passphrase(pw);
1261 1.1 christos if (change_comment)
1262 1.1 christos do_change_comment(pw);
1263 1.1 christos if (convert_to_ssh2)
1264 1.1 christos do_convert_to_ssh2(pw);
1265 1.1 christos if (convert_from_ssh2)
1266 1.1 christos do_convert_from_ssh2(pw);
1267 1.1 christos if (print_public)
1268 1.1 christos do_print_public(pw);
1269 1.1 christos if (rr_hostname != NULL) {
1270 1.1 christos unsigned int n = 0;
1271 1.1 christos
1272 1.1 christos if (have_identity) {
1273 1.1 christos n = do_print_resource_record(pw,
1274 1.1 christos identity_file, rr_hostname);
1275 1.1 christos if (n == 0) {
1276 1.1 christos perror(identity_file);
1277 1.1 christos exit(1);
1278 1.1 christos }
1279 1.1 christos exit(0);
1280 1.1 christos } else {
1281 1.1 christos
1282 1.1 christos n += do_print_resource_record(pw,
1283 1.1 christos _PATH_HOST_RSA_KEY_FILE, rr_hostname);
1284 1.1 christos n += do_print_resource_record(pw,
1285 1.1 christos _PATH_HOST_DSA_KEY_FILE, rr_hostname);
1286 1.1 christos
1287 1.1 christos if (n == 0)
1288 1.1 christos fatal("no keys found.");
1289 1.1 christos exit(0);
1290 1.1 christos }
1291 1.1 christos }
1292 1.1 christos if (reader_id != NULL) {
1293 1.1 christos #ifdef SMARTCARD
1294 1.1 christos if (download)
1295 1.1 christos do_download(pw, reader_id);
1296 1.1 christos else
1297 1.1 christos do_upload(pw, reader_id);
1298 1.1 christos #else /* SMARTCARD */
1299 1.1 christos fatal("no support for smartcards.");
1300 1.1 christos #endif /* SMARTCARD */
1301 1.1 christos }
1302 1.1 christos
1303 1.1 christos if (do_gen_candidates) {
1304 1.1 christos FILE *out = fopen(out_file, "w");
1305 1.1 christos
1306 1.1 christos if (out == NULL) {
1307 1.1 christos error("Couldn't open modulus candidate file \"%s\": %s",
1308 1.1 christos out_file, strerror(errno));
1309 1.1 christos return (1);
1310 1.1 christos }
1311 1.1 christos if (bits == 0)
1312 1.1 christos bits = DEFAULT_BITS;
1313 1.1 christos if (gen_candidates(out, memory, bits, start) != 0)
1314 1.1 christos fatal("modulus candidate generation failed");
1315 1.1 christos
1316 1.1 christos return (0);
1317 1.1 christos }
1318 1.1 christos
1319 1.1 christos if (do_screen_candidates) {
1320 1.1 christos FILE *in;
1321 1.1 christos FILE *out = fopen(out_file, "w");
1322 1.1 christos
1323 1.1 christos if (have_identity && strcmp(identity_file, "-") != 0) {
1324 1.1 christos if ((in = fopen(identity_file, "r")) == NULL) {
1325 1.1 christos fatal("Couldn't open modulus candidate "
1326 1.1 christos "file \"%s\": %s", identity_file,
1327 1.1 christos strerror(errno));
1328 1.1 christos }
1329 1.1 christos } else
1330 1.1 christos in = stdin;
1331 1.1 christos
1332 1.1 christos if (out == NULL) {
1333 1.1 christos fatal("Couldn't open moduli file \"%s\": %s",
1334 1.1 christos out_file, strerror(errno));
1335 1.1 christos }
1336 1.1 christos if (prime_test(in, out, trials, generator_wanted) != 0)
1337 1.1 christos fatal("modulus screening failed");
1338 1.1 christos return (0);
1339 1.1 christos }
1340 1.1 christos
1341 1.1 christos arc4random_stir();
1342 1.1 christos
1343 1.1 christos if (key_type_name == NULL)
1344 1.1 christos key_type_name = "rsa";
1345 1.1 christos
1346 1.1 christos type = key_type_from_name(key_type_name);
1347 1.1 christos if (type == KEY_UNSPEC) {
1348 1.1 christos fprintf(stderr, "unknown key type %s\n", key_type_name);
1349 1.1 christos exit(1);
1350 1.1 christos }
1351 1.1 christos if (bits == 0)
1352 1.1 christos bits = (type == KEY_DSA) ? DEFAULT_BITS_DSA : DEFAULT_BITS;
1353 1.1 christos if (type == KEY_DSA && bits != 1024)
1354 1.1 christos fatal("DSA keys must be 1024 bits");
1355 1.1 christos if (!quiet)
1356 1.1 christos printf("Generating public/private %s key pair.\n", key_type_name);
1357 1.1 christos private = key_generate(type, bits);
1358 1.1 christos if (private == NULL) {
1359 1.1 christos fprintf(stderr, "key_generate failed\n");
1360 1.1 christos exit(1);
1361 1.1 christos }
1362 1.1 christos public = key_from_private(private);
1363 1.1 christos
1364 1.1 christos if (!have_identity)
1365 1.1 christos ask_filename(pw, "Enter file in which to save the key");
1366 1.1 christos
1367 1.1 christos /* Create ~/.ssh directory if it doesn't already exist. */
1368 1.1 christos snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR);
1369 1.1 christos if (strstr(identity_file, dotsshdir) != NULL &&
1370 1.1 christos stat(dotsshdir, &st) < 0) {
1371 1.1 christos if (mkdir(dotsshdir, 0700) < 0)
1372 1.1 christos error("Could not create directory '%s'.", dotsshdir);
1373 1.1 christos else if (!quiet)
1374 1.1 christos printf("Created directory '%s'.\n", dotsshdir);
1375 1.1 christos }
1376 1.1 christos /* If the file already exists, ask the user to confirm. */
1377 1.1 christos if (stat(identity_file, &st) >= 0) {
1378 1.1 christos char yesno[3];
1379 1.1 christos printf("%s already exists.\n", identity_file);
1380 1.1 christos printf("Overwrite (y/n)? ");
1381 1.1 christos fflush(stdout);
1382 1.1 christos if (fgets(yesno, sizeof(yesno), stdin) == NULL)
1383 1.1 christos exit(1);
1384 1.1 christos if (yesno[0] != 'y' && yesno[0] != 'Y')
1385 1.1 christos exit(1);
1386 1.1 christos }
1387 1.1 christos /* Ask for a passphrase (twice). */
1388 1.1 christos if (identity_passphrase)
1389 1.1 christos passphrase1 = xstrdup(identity_passphrase);
1390 1.1 christos else if (identity_new_passphrase)
1391 1.1 christos passphrase1 = xstrdup(identity_new_passphrase);
1392 1.1 christos else {
1393 1.1 christos passphrase_again:
1394 1.1 christos passphrase1 =
1395 1.1 christos read_passphrase("Enter passphrase (empty for no "
1396 1.1 christos "passphrase): ", RP_ALLOW_STDIN);
1397 1.1 christos passphrase2 = read_passphrase("Enter same passphrase again: ",
1398 1.1 christos RP_ALLOW_STDIN);
1399 1.1 christos if (strcmp(passphrase1, passphrase2) != 0) {
1400 1.1 christos /*
1401 1.1 christos * The passphrases do not match. Clear them and
1402 1.1 christos * retry.
1403 1.1 christos */
1404 1.1 christos memset(passphrase1, 0, strlen(passphrase1));
1405 1.1 christos memset(passphrase2, 0, strlen(passphrase2));
1406 1.1 christos xfree(passphrase1);
1407 1.1 christos xfree(passphrase2);
1408 1.1 christos printf("Passphrases do not match. Try again.\n");
1409 1.1 christos goto passphrase_again;
1410 1.1 christos }
1411 1.1 christos /* Clear the other copy of the passphrase. */
1412 1.1 christos memset(passphrase2, 0, strlen(passphrase2));
1413 1.1 christos xfree(passphrase2);
1414 1.1 christos }
1415 1.1 christos
1416 1.1 christos if (identity_comment) {
1417 1.1 christos strlcpy(comment, identity_comment, sizeof(comment));
1418 1.1 christos } else {
1419 1.1 christos /* Create default comment field for the passphrase. */
1420 1.1 christos snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
1421 1.1 christos }
1422 1.1 christos
1423 1.1 christos /* Save the key with the given passphrase and comment. */
1424 1.1 christos if (!key_save_private(private, identity_file, passphrase1, comment)) {
1425 1.1 christos printf("Saving the key failed: %s.\n", identity_file);
1426 1.1 christos memset(passphrase1, 0, strlen(passphrase1));
1427 1.1 christos xfree(passphrase1);
1428 1.1 christos exit(1);
1429 1.1 christos }
1430 1.1 christos /* Clear the passphrase. */
1431 1.1 christos memset(passphrase1, 0, strlen(passphrase1));
1432 1.1 christos xfree(passphrase1);
1433 1.1 christos
1434 1.1 christos /* Clear the private key and the random number generator. */
1435 1.1 christos key_free(private);
1436 1.1 christos arc4random_stir();
1437 1.1 christos
1438 1.1 christos if (!quiet)
1439 1.1 christos printf("Your identification has been saved in %s.\n", identity_file);
1440 1.1 christos
1441 1.1 christos strlcat(identity_file, ".pub", sizeof(identity_file));
1442 1.1 christos fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1443 1.1 christos if (fd == -1) {
1444 1.1 christos printf("Could not save your public key in %s\n", identity_file);
1445 1.1 christos exit(1);
1446 1.1 christos }
1447 1.1 christos f = fdopen(fd, "w");
1448 1.1 christos if (f == NULL) {
1449 1.1 christos printf("fdopen %s failed\n", identity_file);
1450 1.1 christos exit(1);
1451 1.1 christos }
1452 1.1 christos if (!key_write(public, f))
1453 1.1 christos fprintf(stderr, "write key failed\n");
1454 1.1 christos fprintf(f, " %s\n", comment);
1455 1.1 christos fclose(f);
1456 1.1 christos
1457 1.1 christos if (!quiet) {
1458 1.1 christos char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
1459 1.1 christos char *ra = key_fingerprint(public, SSH_FP_MD5,
1460 1.1 christos SSH_FP_RANDOMART);
1461 1.1 christos printf("Your public key has been saved in %s.\n",
1462 1.1 christos identity_file);
1463 1.1 christos printf("The key fingerprint is:\n");
1464 1.1 christos printf("%s %s\n", fp, comment);
1465 1.1 christos printf("The key's randomart image is:\n");
1466 1.1 christos printf("%s\n", ra);
1467 1.1 christos xfree(ra);
1468 1.1 christos xfree(fp);
1469 1.1 christos }
1470 1.1 christos
1471 1.1 christos key_free(public);
1472 1.1 christos exit(0);
1473 1.1 christos }
1474