summaryrefslogtreecommitdiff
path: root/ssh-keygen.c
diff options
context:
space:
mode:
Diffstat (limited to 'ssh-keygen.c')
-rw-r--r--ssh-keygen.c594
1 files changed, 488 insertions, 106 deletions
diff --git a/ssh-keygen.c b/ssh-keygen.c
index 3898b281e..8c829cad6 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-keygen.c,v 1.329 2019/03/25 16:19:44 dtucker Exp $ */ 1/* $OpenBSD: ssh-keygen.c,v 1.355 2019/10/03 17:07:50 jmc Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -24,6 +24,9 @@
24#include "openbsd-compat/openssl-compat.h" 24#include "openbsd-compat/openssl-compat.h"
25#endif 25#endif
26 26
27#ifdef HAVE_STDINT_H
28# include <stdint.h>
29#endif
27#include <errno.h> 30#include <errno.h>
28#include <fcntl.h> 31#include <fcntl.h>
29#include <netdb.h> 32#include <netdb.h>
@@ -43,7 +46,6 @@
43#include "xmalloc.h" 46#include "xmalloc.h"
44#include "sshkey.h" 47#include "sshkey.h"
45#include "authfile.h" 48#include "authfile.h"
46#include "uuencode.h"
47#include "sshbuf.h" 49#include "sshbuf.h"
48#include "pathnames.h" 50#include "pathnames.h"
49#include "log.h" 51#include "log.h"
@@ -60,6 +62,7 @@
60#include "digest.h" 62#include "digest.h"
61#include "utf8.h" 63#include "utf8.h"
62#include "authfd.h" 64#include "authfd.h"
65#include "sshsig.h"
63 66
64#ifdef WITH_OPENSSL 67#ifdef WITH_OPENSSL
65# define DEFAULT_KEY_TYPE_NAME "rsa" 68# define DEFAULT_KEY_TYPE_NAME "rsa"
@@ -92,7 +95,7 @@ static int print_bubblebabble = 0;
92static int fingerprint_hash = SSH_FP_HASH_DEFAULT; 95static int fingerprint_hash = SSH_FP_HASH_DEFAULT;
93 96
94/* The identity file name, given on the command line or entered by the user. */ 97/* The identity file name, given on the command line or entered by the user. */
95static char identity_file[1024]; 98static char identity_file[PATH_MAX];
96static int have_identity = 0; 99static int have_identity = 0;
97 100
98/* This is set to the passphrase if given on the command line. */ 101/* This is set to the passphrase if given on the command line. */
@@ -147,11 +150,11 @@ static char *key_type_name = NULL;
147/* Load key from this PKCS#11 provider */ 150/* Load key from this PKCS#11 provider */
148static char *pkcs11provider = NULL; 151static char *pkcs11provider = NULL;
149 152
150/* Use new OpenSSH private key format when writing SSH2 keys instead of PEM */ 153/* Format for writing private keys */
151static int use_new_format = 1; 154static int private_key_format = SSHKEY_PRIVATE_OPENSSH;
152 155
153/* Cipher for new-format private keys */ 156/* Cipher for new-format private keys */
154static char *new_format_cipher = NULL; 157static char *openssh_format_cipher = NULL;
155 158
156/* 159/*
157 * Number of KDF rounds to derive new format keys / 160 * Number of KDF rounds to derive new format keys /
@@ -174,31 +177,30 @@ int prime_test(FILE *, FILE *, u_int32_t, u_int32_t, char *, unsigned long,
174static void 177static void
175type_bits_valid(int type, const char *name, u_int32_t *bitsp) 178type_bits_valid(int type, const char *name, u_int32_t *bitsp)
176{ 179{
177#ifdef WITH_OPENSSL
178 u_int maxbits, nid;
179#endif
180
181 if (type == KEY_UNSPEC) 180 if (type == KEY_UNSPEC)
182 fatal("unknown key type %s", key_type_name); 181 fatal("unknown key type %s", key_type_name);
183 if (*bitsp == 0) { 182 if (*bitsp == 0) {
184#ifdef WITH_OPENSSL 183#ifdef WITH_OPENSSL
185 if (type == KEY_DSA) 184 u_int nid;
185
186 switch(type) {
187 case KEY_DSA:
186 *bitsp = DEFAULT_BITS_DSA; 188 *bitsp = DEFAULT_BITS_DSA;
187 else if (type == KEY_ECDSA) { 189 break;
190 case KEY_ECDSA:
188 if (name != NULL && 191 if (name != NULL &&
189 (nid = sshkey_ecdsa_nid_from_name(name)) > 0) 192 (nid = sshkey_ecdsa_nid_from_name(name)) > 0)
190 *bitsp = sshkey_curve_nid_to_bits(nid); 193 *bitsp = sshkey_curve_nid_to_bits(nid);
191 if (*bitsp == 0) 194 if (*bitsp == 0)
192 *bitsp = DEFAULT_BITS_ECDSA; 195 *bitsp = DEFAULT_BITS_ECDSA;
193 } else 196 break;
194#endif 197 case KEY_RSA:
195 *bitsp = DEFAULT_BITS; 198 *bitsp = DEFAULT_BITS;
199 break;
200 }
201#endif
196 } 202 }
197#ifdef WITH_OPENSSL 203#ifdef WITH_OPENSSL
198 maxbits = (type == KEY_DSA) ?
199 OPENSSL_DSA_MAX_MODULUS_BITS : OPENSSL_RSA_MAX_MODULUS_BITS;
200 if (*bitsp > maxbits)
201 fatal("key bits exceeds maximum %d", maxbits);
202 switch (type) { 204 switch (type) {
203 case KEY_DSA: 205 case KEY_DSA:
204 if (*bitsp != 1024) 206 if (*bitsp != 1024)
@@ -208,6 +210,9 @@ type_bits_valid(int type, const char *name, u_int32_t *bitsp)
208 if (*bitsp < SSH_RSA_MINIMUM_MODULUS_SIZE) 210 if (*bitsp < SSH_RSA_MINIMUM_MODULUS_SIZE)
209 fatal("Invalid RSA key length: minimum is %d bits", 211 fatal("Invalid RSA key length: minimum is %d bits",
210 SSH_RSA_MINIMUM_MODULUS_SIZE); 212 SSH_RSA_MINIMUM_MODULUS_SIZE);
213 else if (*bitsp > OPENSSL_RSA_MAX_MODULUS_BITS)
214 fatal("Invalid RSA key length: maximum is %d bits",
215 OPENSSL_RSA_MAX_MODULUS_BITS);
211 break; 216 break;
212 case KEY_ECDSA: 217 case KEY_ECDSA:
213 if (sshkey_ecdsa_bits_to_nid(*bitsp) == -1) 218 if (sshkey_ecdsa_bits_to_nid(*bitsp) == -1)
@@ -221,6 +226,30 @@ type_bits_valid(int type, const char *name, u_int32_t *bitsp)
221#endif 226#endif
222} 227}
223 228
229/*
230 * Checks whether a file exists and, if so, asks the user whether they wish
231 * to overwrite it.
232 * Returns nonzero if the file does not already exist or if the user agrees to
233 * overwrite, or zero otherwise.
234 */
235static int
236confirm_overwrite(const char *filename)
237{
238 char yesno[3];
239 struct stat st;
240
241 if (stat(filename, &st) != 0)
242 return 1;
243 printf("%s already exists.\n", filename);
244 printf("Overwrite (y/n)? ");
245 fflush(stdout);
246 if (fgets(yesno, sizeof(yesno), stdin) == NULL)
247 return 0;
248 if (yesno[0] != 'y' && yesno[0] != 'Y')
249 return 0;
250 return 1;
251}
252
224static void 253static void
225ask_filename(struct passwd *pw, const char *prompt) 254ask_filename(struct passwd *pw, const char *prompt)
226{ 255{
@@ -270,13 +299,15 @@ ask_filename(struct passwd *pw, const char *prompt)
270} 299}
271 300
272static struct sshkey * 301static struct sshkey *
273load_identity(char *filename) 302load_identity(const char *filename, char **commentp)
274{ 303{
275 char *pass; 304 char *pass;
276 struct sshkey *prv; 305 struct sshkey *prv;
277 int r; 306 int r;
278 307
279 if ((r = sshkey_load_private(filename, "", &prv, NULL)) == 0) 308 if (commentp != NULL)
309 *commentp = NULL;
310 if ((r = sshkey_load_private(filename, "", &prv, commentp)) == 0)
280 return prv; 311 return prv;
281 if (r != SSH_ERR_KEY_WRONG_PASSPHRASE) 312 if (r != SSH_ERR_KEY_WRONG_PASSPHRASE)
282 fatal("Load key \"%s\": %s", filename, ssh_err(r)); 313 fatal("Load key \"%s\": %s", filename, ssh_err(r));
@@ -284,7 +315,7 @@ load_identity(char *filename)
284 pass = xstrdup(identity_passphrase); 315 pass = xstrdup(identity_passphrase);
285 else 316 else
286 pass = read_passphrase("Enter passphrase: ", RP_ALLOW_STDIN); 317 pass = read_passphrase("Enter passphrase: ", RP_ALLOW_STDIN);
287 r = sshkey_load_private(filename, pass, &prv, NULL); 318 r = sshkey_load_private(filename, pass, &prv, commentp);
288 explicit_bzero(pass, strlen(pass)); 319 explicit_bzero(pass, strlen(pass));
289 free(pass); 320 free(pass);
290 if (r != 0) 321 if (r != 0)
@@ -301,25 +332,30 @@ load_identity(char *filename)
301static void 332static void
302do_convert_to_ssh2(struct passwd *pw, struct sshkey *k) 333do_convert_to_ssh2(struct passwd *pw, struct sshkey *k)
303{ 334{
304 size_t len; 335 struct sshbuf *b;
305 u_char *blob; 336 char comment[61], *b64;
306 char comment[61];
307 int r; 337 int r;
308 338
309 if ((r = sshkey_to_blob(k, &blob, &len)) != 0) 339 if ((b = sshbuf_new()) == NULL)
340 fatal("%s: sshbuf_new failed", __func__);
341 if ((r = sshkey_putb(k, b)) != 0)
310 fatal("key_to_blob failed: %s", ssh_err(r)); 342 fatal("key_to_blob failed: %s", ssh_err(r));
343 if ((b64 = sshbuf_dtob64_string(b, 1)) == NULL)
344 fatal("%s: sshbuf_dtob64_string failed", __func__);
345
311 /* Comment + surrounds must fit into 72 chars (RFC 4716 sec 3.3) */ 346 /* Comment + surrounds must fit into 72 chars (RFC 4716 sec 3.3) */
312 snprintf(comment, sizeof(comment), 347 snprintf(comment, sizeof(comment),
313 "%u-bit %s, converted by %s@%s from OpenSSH", 348 "%u-bit %s, converted by %s@%s from OpenSSH",
314 sshkey_size(k), sshkey_type(k), 349 sshkey_size(k), sshkey_type(k),
315 pw->pw_name, hostname); 350 pw->pw_name, hostname);
316 351
352 sshkey_free(k);
353 sshbuf_free(b);
354
317 fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN); 355 fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
318 fprintf(stdout, "Comment: \"%s\"\n", comment); 356 fprintf(stdout, "Comment: \"%s\"\n%s", comment, b64);
319 dump_base64(stdout, blob, len);
320 fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END); 357 fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
321 sshkey_free(k); 358 free(b64);
322 free(blob);
323 exit(0); 359 exit(0);
324} 360}
325 361
@@ -370,10 +406,10 @@ do_convert_to(struct passwd *pw)
370 406
371 if (!have_identity) 407 if (!have_identity)
372 ask_filename(pw, "Enter file in which the key is"); 408 ask_filename(pw, "Enter file in which the key is");
373 if (stat(identity_file, &st) < 0) 409 if (stat(identity_file, &st) == -1)
374 fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); 410 fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
375 if ((r = sshkey_load_public(identity_file, &k, NULL)) != 0) 411 if ((r = sshkey_load_public(identity_file, &k, NULL)) != 0)
376 k = load_identity(identity_file); 412 k = load_identity(identity_file, NULL);
377 switch (convert_format) { 413 switch (convert_format) {
378 case FMT_RFC4716: 414 case FMT_RFC4716:
379 do_convert_to_ssh2(pw, k); 415 do_convert_to_ssh2(pw, k);
@@ -413,9 +449,8 @@ buffer_get_bignum_bits(struct sshbuf *b, BIGNUM *value)
413} 449}
414 450
415static struct sshkey * 451static struct sshkey *
416do_convert_private_ssh2_from_blob(u_char *blob, u_int blen) 452do_convert_private_ssh2(struct sshbuf *b)
417{ 453{
418 struct sshbuf *b;
419 struct sshkey *key = NULL; 454 struct sshkey *key = NULL;
420 char *type, *cipher; 455 char *type, *cipher;
421 u_char e1, e2, e3, *sig = NULL, data[] = "abcde12345"; 456 u_char e1, e2, e3, *sig = NULL, data[] = "abcde12345";
@@ -427,15 +462,13 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen)
427 BIGNUM *dsa_pub_key = NULL, *dsa_priv_key = NULL; 462 BIGNUM *dsa_pub_key = NULL, *dsa_priv_key = NULL;
428 BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL; 463 BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL;
429 BIGNUM *rsa_p = NULL, *rsa_q = NULL, *rsa_iqmp = NULL; 464 BIGNUM *rsa_p = NULL, *rsa_q = NULL, *rsa_iqmp = NULL;
430 if ((b = sshbuf_from(blob, blen)) == NULL) 465
431 fatal("%s: sshbuf_from failed", __func__);
432 if ((r = sshbuf_get_u32(b, &magic)) != 0) 466 if ((r = sshbuf_get_u32(b, &magic)) != 0)
433 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 467 fatal("%s: buffer error: %s", __func__, ssh_err(r));
434 468
435 if (magic != SSH_COM_PRIVATE_KEY_MAGIC) { 469 if (magic != SSH_COM_PRIVATE_KEY_MAGIC) {
436 error("bad magic 0x%x != 0x%x", magic, 470 error("bad magic 0x%x != 0x%x", magic,
437 SSH_COM_PRIVATE_KEY_MAGIC); 471 SSH_COM_PRIVATE_KEY_MAGIC);
438 sshbuf_free(b);
439 return NULL; 472 return NULL;
440 } 473 }
441 if ((r = sshbuf_get_u32(b, &i1)) != 0 || 474 if ((r = sshbuf_get_u32(b, &i1)) != 0 ||
@@ -449,7 +482,6 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen)
449 if (strcmp(cipher, "none") != 0) { 482 if (strcmp(cipher, "none") != 0) {
450 error("unsupported cipher %s", cipher); 483 error("unsupported cipher %s", cipher);
451 free(cipher); 484 free(cipher);
452 sshbuf_free(b);
453 free(type); 485 free(type);
454 return NULL; 486 return NULL;
455 } 487 }
@@ -460,7 +492,6 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen)
460 } else if (strstr(type, "rsa")) { 492 } else if (strstr(type, "rsa")) {
461 ktype = KEY_RSA; 493 ktype = KEY_RSA;
462 } else { 494 } else {
463 sshbuf_free(b);
464 free(type); 495 free(type);
465 return NULL; 496 return NULL;
466 } 497 }
@@ -507,7 +538,6 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen)
507 fatal("%s: BN_new", __func__); 538 fatal("%s: BN_new", __func__);
508 if (!BN_set_word(rsa_e, e)) { 539 if (!BN_set_word(rsa_e, e)) {
509 BN_clear_free(rsa_e); 540 BN_clear_free(rsa_e);
510 sshbuf_free(b);
511 sshkey_free(key); 541 sshkey_free(key);
512 return NULL; 542 return NULL;
513 } 543 }
@@ -535,9 +565,7 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen)
535 } 565 }
536 rlen = sshbuf_len(b); 566 rlen = sshbuf_len(b);
537 if (rlen != 0) 567 if (rlen != 0)
538 error("do_convert_private_ssh2_from_blob: " 568 error("%s: remaining bytes in key blob %d", __func__, rlen);
539 "remaining bytes in key blob %d", rlen);
540 sshbuf_free(b);
541 569
542 /* try the key */ 570 /* try the key */
543 if (sshkey_sign(key, &sig, &slen, data, sizeof(data), NULL, 0) != 0 || 571 if (sshkey_sign(key, &sig, &slen, data, sizeof(data), NULL, 0) != 0 ||
@@ -582,10 +610,12 @@ do_convert_from_ssh2(struct passwd *pw, struct sshkey **k, int *private)
582 int r, blen, escaped = 0; 610 int r, blen, escaped = 0;
583 u_int len; 611 u_int len;
584 char line[1024]; 612 char line[1024];
585 u_char blob[8096]; 613 struct sshbuf *buf;
586 char encoded[8096]; 614 char encoded[8096];
587 FILE *fp; 615 FILE *fp;
588 616
617 if ((buf = sshbuf_new()) == NULL)
618 fatal("sshbuf_new failed");
589 if ((fp = fopen(identity_file, "r")) == NULL) 619 if ((fp = fopen(identity_file, "r")) == NULL)
590 fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); 620 fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
591 encoded[0] = '\0'; 621 encoded[0] = '\0';
@@ -615,12 +645,11 @@ do_convert_from_ssh2(struct passwd *pw, struct sshkey **k, int *private)
615 (encoded[len-2] == '=') && 645 (encoded[len-2] == '=') &&
616 (encoded[len-3] == '=')) 646 (encoded[len-3] == '='))
617 encoded[len-3] = '\0'; 647 encoded[len-3] = '\0';
618 blen = uudecode(encoded, blob, sizeof(blob)); 648 if ((r = sshbuf_b64tod(buf, encoded)) != 0)
619 if (blen < 0) 649 fatal("%s: base64 decoding failed: %s", __func__, ssh_err(r));
620 fatal("uudecode failed.");
621 if (*private) 650 if (*private)
622 *k = do_convert_private_ssh2_from_blob(blob, blen); 651 *k = do_convert_private_ssh2(buf);
623 else if ((r = sshkey_from_blob(blob, blen, k)) != 0) 652 else if ((r = sshkey_fromb(buf, k)) != 0)
624 fatal("decode blob failed: %s", ssh_err(r)); 653 fatal("decode blob failed: %s", ssh_err(r));
625 fclose(fp); 654 fclose(fp);
626} 655}
@@ -696,7 +725,7 @@ do_convert_from(struct passwd *pw)
696 725
697 if (!have_identity) 726 if (!have_identity)
698 ask_filename(pw, "Enter file in which the key is"); 727 ask_filename(pw, "Enter file in which the key is");
699 if (stat(identity_file, &st) < 0) 728 if (stat(identity_file, &st) == -1)
700 fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); 729 fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
701 730
702 switch (convert_format) { 731 switch (convert_format) {
@@ -753,16 +782,20 @@ do_print_public(struct passwd *pw)
753 struct sshkey *prv; 782 struct sshkey *prv;
754 struct stat st; 783 struct stat st;
755 int r; 784 int r;
785 char *comment = NULL;
756 786
757 if (!have_identity) 787 if (!have_identity)
758 ask_filename(pw, "Enter file in which the key is"); 788 ask_filename(pw, "Enter file in which the key is");
759 if (stat(identity_file, &st) < 0) 789 if (stat(identity_file, &st) == -1)
760 fatal("%s: %s", identity_file, strerror(errno)); 790 fatal("%s: %s", identity_file, strerror(errno));
761 prv = load_identity(identity_file); 791 prv = load_identity(identity_file, &comment);
762 if ((r = sshkey_write(prv, stdout)) != 0) 792 if ((r = sshkey_write(prv, stdout)) != 0)
763 error("sshkey_write failed: %s", ssh_err(r)); 793 error("sshkey_write failed: %s", ssh_err(r));
764 sshkey_free(prv); 794 sshkey_free(prv);
795 if (comment != NULL && *comment != '\0')
796 fprintf(stdout, " %s", comment);
765 fprintf(stdout, "\n"); 797 fprintf(stdout, "\n");
798 free(comment);
766 exit(0); 799 exit(0);
767} 800}
768 801
@@ -854,7 +887,7 @@ fingerprint_private(const char *path)
854 struct sshkey *public = NULL; 887 struct sshkey *public = NULL;
855 int r; 888 int r;
856 889
857 if (stat(identity_file, &st) < 0) 890 if (stat(identity_file, &st) == -1)
858 fatal("%s: %s", path, strerror(errno)); 891 fatal("%s: %s", path, strerror(errno));
859 if ((r = sshkey_load_public(path, &public, &comment)) != 0) { 892 if ((r = sshkey_load_public(path, &public, &comment)) != 0) {
860 debug("load public \"%s\": %s", path, ssh_err(r)); 893 debug("load public \"%s\": %s", path, ssh_err(r));
@@ -988,7 +1021,7 @@ do_gen_all_hostkeys(struct passwd *pw)
988 { NULL, NULL, NULL } 1021 { NULL, NULL, NULL }
989 }; 1022 };
990 1023
991 u_int bits = 0; 1024 u_int32_t bits = 0;
992 int first = 0; 1025 int first = 0;
993 struct stat st; 1026 struct stat st;
994 struct sshkey *private, *public; 1027 struct sshkey *private, *public;
@@ -1048,7 +1081,8 @@ do_gen_all_hostkeys(struct passwd *pw)
1048 snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, 1081 snprintf(comment, sizeof comment, "%s@%s", pw->pw_name,
1049 hostname); 1082 hostname);
1050 if ((r = sshkey_save_private(private, prv_tmp, "", 1083 if ((r = sshkey_save_private(private, prv_tmp, "",
1051 comment, use_new_format, new_format_cipher, rounds)) != 0) { 1084 comment, private_key_format, openssh_format_cipher,
1085 rounds)) != 0) {
1052 error("Saving key \"%s\" failed: %s", 1086 error("Saving key \"%s\" failed: %s",
1053 prv_tmp, ssh_err(r)); 1087 prv_tmp, ssh_err(r));
1054 goto failnext; 1088 goto failnext;
@@ -1174,7 +1208,7 @@ known_hosts_find_delete(struct hostkey_foreach_line *l, void *_ctx)
1174 struct known_hosts_ctx *ctx = (struct known_hosts_ctx *)_ctx; 1208 struct known_hosts_ctx *ctx = (struct known_hosts_ctx *)_ctx;
1175 enum sshkey_fp_rep rep; 1209 enum sshkey_fp_rep rep;
1176 int fptype; 1210 int fptype;
1177 char *fp; 1211 char *fp = NULL, *ra = NULL;
1178 1212
1179 fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash; 1213 fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash;
1180 rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT; 1214 rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT;
@@ -1208,8 +1242,16 @@ known_hosts_find_delete(struct hostkey_foreach_line *l, void *_ctx)
1208 known_hosts_hash(l, ctx); 1242 known_hosts_hash(l, ctx);
1209 else if (print_fingerprint) { 1243 else if (print_fingerprint) {
1210 fp = sshkey_fingerprint(l->key, fptype, rep); 1244 fp = sshkey_fingerprint(l->key, fptype, rep);
1245 ra = sshkey_fingerprint(l->key,
1246 fingerprint_hash, SSH_FP_RANDOMART);
1247 if (fp == NULL || ra == NULL)
1248 fatal("%s: sshkey_fingerprint failed",
1249 __func__);
1211 mprintf("%s %s %s %s\n", ctx->host, 1250 mprintf("%s %s %s %s\n", ctx->host,
1212 sshkey_type(l->key), fp, l->comment); 1251 sshkey_type(l->key), fp, l->comment);
1252 if (log_level_get() >= SYSLOG_LEVEL_VERBOSE)
1253 printf("%s\n", ra);
1254 free(ra);
1213 free(fp); 1255 free(fp);
1214 } else 1256 } else
1215 fprintf(ctx->out, "%s\n", l->line); 1257 fprintf(ctx->out, "%s\n", l->line);
@@ -1340,7 +1382,7 @@ do_change_passphrase(struct passwd *pw)
1340 1382
1341 if (!have_identity) 1383 if (!have_identity)
1342 ask_filename(pw, "Enter file in which the key is"); 1384 ask_filename(pw, "Enter file in which the key is");
1343 if (stat(identity_file, &st) < 0) 1385 if (stat(identity_file, &st) == -1)
1344 fatal("%s: %s", identity_file, strerror(errno)); 1386 fatal("%s: %s", identity_file, strerror(errno));
1345 /* Try to load the file with empty passphrase. */ 1387 /* Try to load the file with empty passphrase. */
1346 r = sshkey_load_private(identity_file, "", &private, &comment); 1388 r = sshkey_load_private(identity_file, "", &private, &comment);
@@ -1391,7 +1433,7 @@ do_change_passphrase(struct passwd *pw)
1391 1433
1392 /* Save the file using the new passphrase. */ 1434 /* Save the file using the new passphrase. */
1393 if ((r = sshkey_save_private(private, identity_file, passphrase1, 1435 if ((r = sshkey_save_private(private, identity_file, passphrase1,
1394 comment, use_new_format, new_format_cipher, rounds)) != 0) { 1436 comment, private_key_format, openssh_format_cipher, rounds)) != 0) {
1395 error("Saving key \"%s\" failed: %s.", 1437 error("Saving key \"%s\" failed: %s.",
1396 identity_file, ssh_err(r)); 1438 identity_file, ssh_err(r));
1397 explicit_bzero(passphrase1, strlen(passphrase1)); 1439 explicit_bzero(passphrase1, strlen(passphrase1));
@@ -1424,7 +1466,7 @@ do_print_resource_record(struct passwd *pw, char *fname, char *hname,
1424 1466
1425 if (fname == NULL) 1467 if (fname == NULL)
1426 fatal("%s: no filename", __func__); 1468 fatal("%s: no filename", __func__);
1427 if (stat(fname, &st) < 0) { 1469 if (stat(fname, &st) == -1) {
1428 if (errno == ENOENT) 1470 if (errno == ENOENT)
1429 return 0; 1471 return 0;
1430 fatal("%s: %s", fname, strerror(errno)); 1472 fatal("%s: %s", fname, strerror(errno));
@@ -1453,7 +1495,7 @@ do_change_comment(struct passwd *pw, const char *identity_comment)
1453 1495
1454 if (!have_identity) 1496 if (!have_identity)
1455 ask_filename(pw, "Enter file in which the key is"); 1497 ask_filename(pw, "Enter file in which the key is");
1456 if (stat(identity_file, &st) < 0) 1498 if (stat(identity_file, &st) == -1)
1457 fatal("%s: %s", identity_file, strerror(errno)); 1499 fatal("%s: %s", identity_file, strerror(errno));
1458 if ((r = sshkey_load_private(identity_file, "", 1500 if ((r = sshkey_load_private(identity_file, "",
1459 &private, &comment)) == 0) 1501 &private, &comment)) == 0)
@@ -1480,7 +1522,7 @@ do_change_comment(struct passwd *pw, const char *identity_comment)
1480 } 1522 }
1481 1523
1482 if (private->type != KEY_ED25519 && private->type != KEY_XMSS && 1524 if (private->type != KEY_ED25519 && private->type != KEY_XMSS &&
1483 !use_new_format) { 1525 private_key_format != SSHKEY_PRIVATE_OPENSSH) {
1484 error("Comments are only supported for keys stored in " 1526 error("Comments are only supported for keys stored in "
1485 "the new format (-o)."); 1527 "the new format (-o).");
1486 explicit_bzero(passphrase, strlen(passphrase)); 1528 explicit_bzero(passphrase, strlen(passphrase));
@@ -1488,14 +1530,14 @@ do_change_comment(struct passwd *pw, const char *identity_comment)
1488 exit(1); 1530 exit(1);
1489 } 1531 }
1490 if (comment) 1532 if (comment)
1491 printf("Key now has comment '%s'\n", comment); 1533 printf("Old comment: %s\n", comment);
1492 else 1534 else
1493 printf("Key now has no comment\n"); 1535 printf("No existing comment\n");
1494 1536
1495 if (identity_comment) { 1537 if (identity_comment) {
1496 strlcpy(new_comment, identity_comment, sizeof(new_comment)); 1538 strlcpy(new_comment, identity_comment, sizeof(new_comment));
1497 } else { 1539 } else {
1498 printf("Enter new comment: "); 1540 printf("New comment: ");
1499 fflush(stdout); 1541 fflush(stdout);
1500 if (!fgets(new_comment, sizeof(new_comment), stdin)) { 1542 if (!fgets(new_comment, sizeof(new_comment), stdin)) {
1501 explicit_bzero(passphrase, strlen(passphrase)); 1543 explicit_bzero(passphrase, strlen(passphrase));
@@ -1504,10 +1546,18 @@ do_change_comment(struct passwd *pw, const char *identity_comment)
1504 } 1546 }
1505 new_comment[strcspn(new_comment, "\n")] = '\0'; 1547 new_comment[strcspn(new_comment, "\n")] = '\0';
1506 } 1548 }
1549 if (comment != NULL && strcmp(comment, new_comment) == 0) {
1550 printf("No change to comment\n");
1551 free(passphrase);
1552 sshkey_free(private);
1553 free(comment);
1554 exit(0);
1555 }
1507 1556
1508 /* Save the file using the new passphrase. */ 1557 /* Save the file using the new passphrase. */
1509 if ((r = sshkey_save_private(private, identity_file, passphrase, 1558 if ((r = sshkey_save_private(private, identity_file, passphrase,
1510 new_comment, use_new_format, new_format_cipher, rounds)) != 0) { 1559 new_comment, private_key_format, openssh_format_cipher,
1560 rounds)) != 0) {
1511 error("Saving key \"%s\" failed: %s", 1561 error("Saving key \"%s\" failed: %s",
1512 identity_file, ssh_err(r)); 1562 identity_file, ssh_err(r));
1513 explicit_bzero(passphrase, strlen(passphrase)); 1563 explicit_bzero(passphrase, strlen(passphrase));
@@ -1537,7 +1587,11 @@ do_change_comment(struct passwd *pw, const char *identity_comment)
1537 1587
1538 free(comment); 1588 free(comment);
1539 1589
1540 printf("The comment in your key file has been changed.\n"); 1590 if (strlen(new_comment) > 0)
1591 printf("Comment '%s' applied\n", new_comment);
1592 else
1593 printf("Comment removed\n");
1594
1541 exit(0); 1595 exit(0);
1542} 1596}
1543 1597
@@ -1643,7 +1697,7 @@ load_pkcs11_key(char *path)
1643 1697
1644/* Signer for sshkey_certify_custom that uses the agent */ 1698/* Signer for sshkey_certify_custom that uses the agent */
1645static int 1699static int
1646agent_signer(const struct sshkey *key, u_char **sigp, size_t *lenp, 1700agent_signer(struct sshkey *key, u_char **sigp, size_t *lenp,
1647 const u_char *data, size_t datalen, 1701 const u_char *data, size_t datalen,
1648 const char *alg, u_int compat, void *ctx) 1702 const char *alg, u_int compat, void *ctx)
1649{ 1703{
@@ -1701,7 +1755,7 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
1701 ca->flags |= SSHKEY_FLAG_EXT; 1755 ca->flags |= SSHKEY_FLAG_EXT;
1702 } else { 1756 } else {
1703 /* CA key is assumed to be a private key on the filesystem */ 1757 /* CA key is assumed to be a private key on the filesystem */
1704 ca = load_identity(tmp); 1758 ca = load_identity(tmp, NULL);
1705 } 1759 }
1706 free(tmp); 1760 free(tmp);
1707 1761
@@ -1726,7 +1780,7 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
1726 } 1780 }
1727 if (n > SSHKEY_CERT_MAX_PRINCIPALS) 1781 if (n > SSHKEY_CERT_MAX_PRINCIPALS)
1728 fatal("Too many certificate principals specified"); 1782 fatal("Too many certificate principals specified");
1729 1783
1730 tmp = tilde_expand_filename(argv[i], pw->pw_uid); 1784 tmp = tilde_expand_filename(argv[i], pw->pw_uid);
1731 if ((r = sshkey_load_public(tmp, &public, &comment)) != 0) 1785 if ((r = sshkey_load_public(tmp, &public, &comment)) != 0)
1732 fatal("%s: unable to open \"%s\": %s", 1786 fatal("%s: unable to open \"%s\": %s",
@@ -2034,7 +2088,7 @@ do_show_cert(struct passwd *pw)
2034 2088
2035 if (!have_identity) 2089 if (!have_identity)
2036 ask_filename(pw, "Enter file in which the key is"); 2090 ask_filename(pw, "Enter file in which the key is");
2037 if (strcmp(identity_file, "-") != 0 && stat(identity_file, &st) < 0) 2091 if (strcmp(identity_file, "-") != 0 && stat(identity_file, &st) == -1)
2038 fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); 2092 fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
2039 2093
2040 path = identity_file; 2094 path = identity_file;
@@ -2372,18 +2426,298 @@ do_check_krl(struct passwd *pw, int argc, char **argv)
2372 exit(ret); 2426 exit(ret);
2373} 2427}
2374 2428
2429static struct sshkey *
2430load_sign_key(const char *keypath, const struct sshkey *pubkey)
2431{
2432 size_t i, slen, plen = strlen(keypath);
2433 char *privpath = xstrdup(keypath);
2434 const char *suffixes[] = { "-cert.pub", ".pub", NULL };
2435 struct sshkey *ret = NULL, *privkey = NULL;
2436 int r;
2437
2438 /*
2439 * If passed a public key filename, then try to locate the correponding
2440 * private key. This lets us specify certificates on the command-line
2441 * and have ssh-keygen find the appropriate private key.
2442 */
2443 for (i = 0; suffixes[i]; i++) {
2444 slen = strlen(suffixes[i]);
2445 if (plen <= slen ||
2446 strcmp(privpath + plen - slen, suffixes[i]) != 0)
2447 continue;
2448 privpath[plen - slen] = '\0';
2449 debug("%s: %s looks like a public key, using private key "
2450 "path %s instead", __func__, keypath, privpath);
2451 }
2452 if ((privkey = load_identity(privpath, NULL)) == NULL) {
2453 error("Couldn't load identity %s", keypath);
2454 goto done;
2455 }
2456 if (!sshkey_equal_public(pubkey, privkey)) {
2457 error("Public key %s doesn't match private %s",
2458 keypath, privpath);
2459 goto done;
2460 }
2461 if (sshkey_is_cert(pubkey) && !sshkey_is_cert(privkey)) {
2462 /*
2463 * Graft the certificate onto the private key to make
2464 * it capable of signing.
2465 */
2466 if ((r = sshkey_to_certified(privkey)) != 0) {
2467 error("%s: sshkey_to_certified: %s", __func__,
2468 ssh_err(r));
2469 goto done;
2470 }
2471 if ((r = sshkey_cert_copy(pubkey, privkey)) != 0) {
2472 error("%s: sshkey_cert_copy: %s", __func__, ssh_err(r));
2473 goto done;
2474 }
2475 }
2476 /* success */
2477 ret = privkey;
2478 privkey = NULL;
2479 done:
2480 sshkey_free(privkey);
2481 free(privpath);
2482 return ret;
2483}
2484
2485static int
2486sign_one(struct sshkey *signkey, const char *filename, int fd,
2487 const char *sig_namespace, sshsig_signer *signer, void *signer_ctx)
2488{
2489 struct sshbuf *sigbuf = NULL, *abuf = NULL;
2490 int r = SSH_ERR_INTERNAL_ERROR, wfd = -1, oerrno;
2491 char *wfile = NULL;
2492 char *asig = NULL;
2493
2494 if (!quiet) {
2495 if (fd == STDIN_FILENO)
2496 fprintf(stderr, "Signing data on standard input\n");
2497 else
2498 fprintf(stderr, "Signing file %s\n", filename);
2499 }
2500 if ((r = sshsig_sign_fd(signkey, NULL, fd, sig_namespace,
2501 &sigbuf, signer, signer_ctx)) != 0) {
2502 error("Signing %s failed: %s", filename, ssh_err(r));
2503 goto out;
2504 }
2505 if ((r = sshsig_armor(sigbuf, &abuf)) != 0) {
2506 error("%s: sshsig_armor: %s", __func__, ssh_err(r));
2507 goto out;
2508 }
2509 if ((asig = sshbuf_dup_string(abuf)) == NULL) {
2510 error("%s: buffer error", __func__);
2511 r = SSH_ERR_ALLOC_FAIL;
2512 goto out;
2513 }
2514
2515 if (fd == STDIN_FILENO) {
2516 fputs(asig, stdout);
2517 fflush(stdout);
2518 } else {
2519 xasprintf(&wfile, "%s.sig", filename);
2520 if (confirm_overwrite(wfile)) {
2521 if ((wfd = open(wfile, O_WRONLY|O_CREAT|O_TRUNC,
2522 0666)) == -1) {
2523 oerrno = errno;
2524 error("Cannot open %s: %s",
2525 wfile, strerror(errno));
2526 errno = oerrno;
2527 r = SSH_ERR_SYSTEM_ERROR;
2528 goto out;
2529 }
2530 if (atomicio(vwrite, wfd, asig,
2531 strlen(asig)) != strlen(asig)) {
2532 oerrno = errno;
2533 error("Cannot write to %s: %s",
2534 wfile, strerror(errno));
2535 errno = oerrno;
2536 r = SSH_ERR_SYSTEM_ERROR;
2537 goto out;
2538 }
2539 if (!quiet) {
2540 fprintf(stderr, "Write signature to %s\n",
2541 wfile);
2542 }
2543 }
2544 }
2545 /* success */
2546 r = 0;
2547 out:
2548 free(wfile);
2549 free(asig);
2550 sshbuf_free(abuf);
2551 sshbuf_free(sigbuf);
2552 if (wfd != -1)
2553 close(wfd);
2554 return r;
2555}
2556
2557static int
2558sign(const char *keypath, const char *sig_namespace, int argc, char **argv)
2559{
2560 int i, fd = -1, r, ret = -1;
2561 int agent_fd = -1;
2562 struct sshkey *pubkey = NULL, *privkey = NULL, *signkey = NULL;
2563 sshsig_signer *signer = NULL;
2564
2565 /* Check file arguments. */
2566 for (i = 0; i < argc; i++) {
2567 if (strcmp(argv[i], "-") != 0)
2568 continue;
2569 if (i > 0 || argc > 1)
2570 fatal("Cannot sign mix of paths and standard input");
2571 }
2572
2573 if ((r = sshkey_load_public(keypath, &pubkey, NULL)) != 0) {
2574 error("Couldn't load public key %s: %s", keypath, ssh_err(r));
2575 goto done;
2576 }
2577
2578 if ((r = ssh_get_authentication_socket(&agent_fd)) != 0)
2579 debug("Couldn't get agent socket: %s", ssh_err(r));
2580 else {
2581 if ((r = ssh_agent_has_key(agent_fd, pubkey)) == 0)
2582 signer = agent_signer;
2583 else
2584 debug("Couldn't find key in agent: %s", ssh_err(r));
2585 }
2586
2587 if (signer == NULL) {
2588 /* Not using agent - try to load private key */
2589 if ((privkey = load_sign_key(keypath, pubkey)) == NULL)
2590 goto done;
2591 signkey = privkey;
2592 } else {
2593 /* Will use key in agent */
2594 signkey = pubkey;
2595 }
2596
2597 if (argc == 0) {
2598 if ((r = sign_one(signkey, "(stdin)", STDIN_FILENO,
2599 sig_namespace, signer, &agent_fd)) != 0)
2600 goto done;
2601 } else {
2602 for (i = 0; i < argc; i++) {
2603 if (strcmp(argv[i], "-") == 0)
2604 fd = STDIN_FILENO;
2605 else if ((fd = open(argv[i], O_RDONLY)) == -1) {
2606 error("Cannot open %s for signing: %s",
2607 argv[i], strerror(errno));
2608 goto done;
2609 }
2610 if ((r = sign_one(signkey, argv[i], fd, sig_namespace,
2611 signer, &agent_fd)) != 0)
2612 goto done;
2613 if (fd != STDIN_FILENO)
2614 close(fd);
2615 fd = -1;
2616 }
2617 }
2618
2619 ret = 0;
2620done:
2621 if (fd != -1 && fd != STDIN_FILENO)
2622 close(fd);
2623 sshkey_free(pubkey);
2624 sshkey_free(privkey);
2625 return ret;
2626}
2627
2628static int
2629verify(const char *signature, const char *sig_namespace, const char *principal,
2630 const char *allowed_keys, const char *revoked_keys)
2631{
2632 int r, ret = -1, sigfd = -1;
2633 struct sshbuf *sigbuf = NULL, *abuf = NULL;
2634 struct sshkey *sign_key = NULL;
2635 char *fp = NULL;
2636
2637 if ((abuf = sshbuf_new()) == NULL)
2638 fatal("%s: sshbuf_new() failed", __func__);
2639
2640 if ((sigfd = open(signature, O_RDONLY)) < 0) {
2641 error("Couldn't open signature file %s", signature);
2642 goto done;
2643 }
2644
2645 if ((r = sshkey_load_file(sigfd, abuf)) != 0) {
2646 error("Couldn't read signature file: %s", ssh_err(r));
2647 goto done;
2648 }
2649 if ((r = sshsig_dearmor(abuf, &sigbuf)) != 0) {
2650 error("%s: sshsig_armor: %s", __func__, ssh_err(r));
2651 return r;
2652 }
2653 if ((r = sshsig_verify_fd(sigbuf, STDIN_FILENO, sig_namespace,
2654 &sign_key)) != 0)
2655 goto done; /* sshsig_verify() prints error */
2656
2657 if ((fp = sshkey_fingerprint(sign_key, fingerprint_hash,
2658 SSH_FP_DEFAULT)) == NULL)
2659 fatal("%s: sshkey_fingerprint failed", __func__);
2660 debug("Valid (unverified) signature from key %s", fp);
2661 free(fp);
2662 fp = NULL;
2663
2664 if (revoked_keys != NULL) {
2665 if ((r = sshkey_check_revoked(sign_key, revoked_keys)) != 0) {
2666 debug3("sshkey_check_revoked failed: %s", ssh_err(r));
2667 goto done;
2668 }
2669 }
2670
2671 if (allowed_keys != NULL &&
2672 (r = sshsig_check_allowed_keys(allowed_keys, sign_key,
2673 principal, sig_namespace)) != 0) {
2674 debug3("sshsig_check_allowed_keys failed: %s", ssh_err(r));
2675 goto done;
2676 }
2677 /* success */
2678 ret = 0;
2679done:
2680 if (!quiet) {
2681 if (ret == 0) {
2682 if ((fp = sshkey_fingerprint(sign_key, fingerprint_hash,
2683 SSH_FP_DEFAULT)) == NULL) {
2684 fatal("%s: sshkey_fingerprint failed",
2685 __func__);
2686 }
2687 if (principal == NULL) {
2688 printf("Good \"%s\" signature with %s key %s\n",
2689 sig_namespace, sshkey_type(sign_key), fp);
2690
2691 } else {
2692 printf("Good \"%s\" signature for %s with %s key %s\n",
2693 sig_namespace, principal,
2694 sshkey_type(sign_key), fp);
2695 }
2696 } else {
2697 printf("Could not verify signature.\n");
2698 }
2699 }
2700 if (sigfd != -1)
2701 close(sigfd);
2702 sshbuf_free(sigbuf);
2703 sshbuf_free(abuf);
2704 sshkey_free(sign_key);
2705 free(fp);
2706 return ret;
2707}
2708
2375static void 2709static void
2376usage(void) 2710usage(void)
2377{ 2711{
2378 fprintf(stderr, 2712 fprintf(stderr,
2379 "usage: ssh-keygen [-q] [-b bits] [-t dsa | ecdsa | ed25519 | rsa] [-m format]\n" 2713 "usage: ssh-keygen [-q] [-b bits] [-C comment] [-f output_keyfile] [-m format]\n"
2380 " [-N new_passphrase] [-C comment] [-f output_keyfile]\n" 2714 " [-N new_passphrase] [-t dsa | ecdsa | ed25519 | rsa]\n"
2381 " ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-m format]\n" 2715 " ssh-keygen -p [-f keyfile] [-m format] [-N new_passphrase]\n"
2382 " [-f keyfile]\n" 2716 " [-P old_passphrase]\n"
2383 " ssh-keygen -i [-m key_format] [-f input_keyfile]\n" 2717 " ssh-keygen -i [-f input_keyfile] [-m key_format]\n"
2384 " ssh-keygen -e [-m key_format] [-f input_keyfile]\n" 2718 " ssh-keygen -e [-f input_keyfile] [-m key_format]\n"
2385 " ssh-keygen -y [-f input_keyfile]\n" 2719 " ssh-keygen -y [-f input_keyfile]\n"
2386 " ssh-keygen -c [-P passphrase] [-C comment] [-f keyfile]\n" 2720 " ssh-keygen -c [-C comment] [-f keyfile] [-P passphrase]\n"
2387 " ssh-keygen -l [-v] [-E fingerprint_hash] [-f input_keyfile]\n" 2721 " ssh-keygen -l [-v] [-E fingerprint_hash] [-f input_keyfile]\n"
2388 " ssh-keygen -B [-f input_keyfile]\n"); 2722 " ssh-keygen -B [-f input_keyfile]\n");
2389#ifdef ENABLE_PKCS11 2723#ifdef ENABLE_PKCS11
@@ -2391,23 +2725,27 @@ usage(void)
2391 " ssh-keygen -D pkcs11\n"); 2725 " ssh-keygen -D pkcs11\n");
2392#endif 2726#endif
2393 fprintf(stderr, 2727 fprintf(stderr,
2394 " ssh-keygen -F hostname [-f known_hosts_file] [-l]\n" 2728 " ssh-keygen -F hostname [-lv] [-f known_hosts_file]\n"
2395 " ssh-keygen -H [-f known_hosts_file]\n" 2729 " ssh-keygen -H [-f known_hosts_file]\n"
2396 " ssh-keygen -R hostname [-f known_hosts_file]\n" 2730 " ssh-keygen -R hostname [-f known_hosts_file]\n"
2397 " ssh-keygen -r hostname [-f input_keyfile] [-g]\n" 2731 " ssh-keygen -r hostname [-g] [-f input_keyfile]\n"
2398#ifdef WITH_OPENSSL 2732#ifdef WITH_OPENSSL
2399 " ssh-keygen -G output_file [-v] [-b bits] [-M memory] [-S start_point]\n" 2733 " ssh-keygen -G output_file [-v] [-b bits] [-M memory] [-S start_point]\n"
2400 " ssh-keygen -T output_file -f input_file [-v] [-a rounds] [-J num_lines]\n" 2734 " ssh-keygen -f input_file -T output_file [-v] [-a rounds] [-J num_lines]\n"
2401 " [-j start_line] [-K checkpt] [-W generator]\n" 2735 " [-j start_line] [-K checkpt] [-W generator]\n"
2402#endif 2736#endif
2403 " ssh-keygen -s ca_key -I certificate_identity [-h] [-U]\n" 2737 " ssh-keygen -I certificate_identity -s ca_key [-hU] [-D pkcs11_provider]\n"
2404 " [-D pkcs11_provider] [-n principals] [-O option]\n" 2738 " [-n principals] [-O option] [-V validity_interval]\n"
2405 " [-V validity_interval] [-z serial_number] file ...\n" 2739 " [-z serial_number] file ...\n"
2406 " ssh-keygen -L [-f input_keyfile]\n" 2740 " ssh-keygen -L [-f input_keyfile]\n"
2407 " ssh-keygen -A\n" 2741 " ssh-keygen -A [-f prefix_path]\n"
2408 " ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n" 2742 " ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n"
2409 " file ...\n" 2743 " file ...\n"
2410 " ssh-keygen -Q -f krl_file file ...\n"); 2744 " ssh-keygen -Q -f krl_file file ...\n"
2745 " ssh-keygen -Y check-novalidate -n namespace -s signature_file\n"
2746 " ssh-keygen -Y sign -f key_file -n namespace file ...\n"
2747 " ssh-keygen -Y verify -f allowed_signers_file -I signer_identity\n"
2748 " -n namespace -s signature_file [-r revocation_file]\n");
2411 exit(1); 2749 exit(1);
2412} 2750}
2413 2751
@@ -2430,10 +2768,11 @@ main(int argc, char **argv)
2430 int print_public = 0, print_generic = 0, cert_serial_autoinc = 0; 2768 int print_public = 0, print_generic = 0, cert_serial_autoinc = 0;
2431 unsigned long long cert_serial = 0; 2769 unsigned long long cert_serial = 0;
2432 char *identity_comment = NULL, *ca_key_path = NULL; 2770 char *identity_comment = NULL, *ca_key_path = NULL;
2433 u_int bits = 0; 2771 u_int32_t bits = 0;
2434 FILE *f; 2772 FILE *f;
2435 const char *errstr; 2773 const char *errstr;
2436 int log_level = SYSLOG_LEVEL_INFO; 2774 int log_level = SYSLOG_LEVEL_INFO;
2775 char *sign_op = NULL;
2437#ifdef WITH_OPENSSL 2776#ifdef WITH_OPENSSL
2438 /* Moduli generation/screening */ 2777 /* Moduli generation/screening */
2439 char out_file[PATH_MAX], *checkpoint = NULL; 2778 char out_file[PATH_MAX], *checkpoint = NULL;
@@ -2446,7 +2785,6 @@ main(int argc, char **argv)
2446 extern int optind; 2785 extern int optind;
2447 extern char *optarg; 2786 extern char *optarg;
2448 2787
2449 ssh_malloc_init(); /* must be called before any mallocs */
2450 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 2788 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
2451 sanitise_stdfd(); 2789 sanitise_stdfd();
2452 2790
@@ -2462,19 +2800,20 @@ main(int argc, char **argv)
2462 pw = getpwuid(getuid()); 2800 pw = getpwuid(getuid());
2463 if (!pw) 2801 if (!pw)
2464 fatal("No user exists for uid %lu", (u_long)getuid()); 2802 fatal("No user exists for uid %lu", (u_long)getuid());
2465 if (gethostname(hostname, sizeof(hostname)) < 0) 2803 if (gethostname(hostname, sizeof(hostname)) == -1)
2466 fatal("gethostname: %s", strerror(errno)); 2804 fatal("gethostname: %s", strerror(errno));
2467 2805
2468 /* Remaining characters: Ydw */ 2806 /* Remaining characters: dw */
2469 while ((opt = getopt(argc, argv, "ABHLQUXceghiklopquvxy" 2807 while ((opt = getopt(argc, argv, "ABHLQUXceghiklopquvxy"
2470 "C:D:E:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:" 2808 "C:D:E:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Y:Z:"
2471 "a:b:f:g:j:m:n:r:s:t:z:")) != -1) { 2809 "a:b:f:g:j:m:n:r:s:t:z:")) != -1) {
2472 switch (opt) { 2810 switch (opt) {
2473 case 'A': 2811 case 'A':
2474 gen_all_hostkeys = 1; 2812 gen_all_hostkeys = 1;
2475 break; 2813 break;
2476 case 'b': 2814 case 'b':
2477 bits = (u_int32_t)strtonum(optarg, 10, 32768, &errstr); 2815 bits = (u_int32_t)strtonum(optarg, 1, UINT32_MAX,
2816 &errstr);
2478 if (errstr) 2817 if (errstr)
2479 fatal("Bits has bad value %s (%s)", 2818 fatal("Bits has bad value %s (%s)",
2480 optarg, errstr); 2819 optarg, errstr);
@@ -2515,11 +2854,12 @@ main(int argc, char **argv)
2515 } 2854 }
2516 if (strcasecmp(optarg, "PKCS8") == 0) { 2855 if (strcasecmp(optarg, "PKCS8") == 0) {
2517 convert_format = FMT_PKCS8; 2856 convert_format = FMT_PKCS8;
2857 private_key_format = SSHKEY_PRIVATE_PKCS8;
2518 break; 2858 break;
2519 } 2859 }
2520 if (strcasecmp(optarg, "PEM") == 0) { 2860 if (strcasecmp(optarg, "PEM") == 0) {
2521 convert_format = FMT_PEM; 2861 convert_format = FMT_PEM;
2522 use_new_format = 0; 2862 private_key_format = SSHKEY_PRIVATE_PEM;
2523 break; 2863 break;
2524 } 2864 }
2525 fatal("Unsupported conversion format \"%s\"", optarg); 2865 fatal("Unsupported conversion format \"%s\"", optarg);
@@ -2557,7 +2897,7 @@ main(int argc, char **argv)
2557 add_cert_option(optarg); 2897 add_cert_option(optarg);
2558 break; 2898 break;
2559 case 'Z': 2899 case 'Z':
2560 new_format_cipher = optarg; 2900 openssh_format_cipher = optarg;
2561 break; 2901 break;
2562 case 'C': 2902 case 'C':
2563 identity_comment = optarg; 2903 identity_comment = optarg;
@@ -2621,6 +2961,9 @@ main(int argc, char **argv)
2621 case 'V': 2961 case 'V':
2622 parse_cert_times(optarg); 2962 parse_cert_times(optarg);
2623 break; 2963 break;
2964 case 'Y':
2965 sign_op = optarg;
2966 break;
2624 case 'z': 2967 case 'z':
2625 errno = 0; 2968 errno = 0;
2626 if (*optarg == '+') { 2969 if (*optarg == '+') {
@@ -2688,6 +3031,50 @@ main(int argc, char **argv)
2688 argv += optind; 3031 argv += optind;
2689 argc -= optind; 3032 argc -= optind;
2690 3033
3034 if (sign_op != NULL) {
3035 if (cert_principals == NULL || *cert_principals == '\0') {
3036 error("Too few arguments for sign/verify: "
3037 "missing namespace");
3038 exit(1);
3039 }
3040 if (strncmp(sign_op, "sign", 4) == 0) {
3041 if (!have_identity) {
3042 error("Too few arguments for sign: "
3043 "missing key");
3044 exit(1);
3045 }
3046 return sign(identity_file, cert_principals, argc, argv);
3047 } else if (strncmp(sign_op, "check-novalidate", 16) == 0) {
3048 if (ca_key_path == NULL) {
3049 error("Too few arguments for check-novalidate: "
3050 "missing signature file");
3051 exit(1);
3052 }
3053 return verify(ca_key_path, cert_principals,
3054 NULL, NULL, NULL);
3055 } else if (strncmp(sign_op, "verify", 6) == 0) {
3056 if (ca_key_path == NULL) {
3057 error("Too few arguments for verify: "
3058 "missing signature file");
3059 exit(1);
3060 }
3061 if (!have_identity) {
3062 error("Too few arguments for sign: "
3063 "missing allowed keys file");
3064 exit(1);
3065 }
3066 if (cert_key_id == NULL) {
3067 error("Too few arguments for verify: "
3068 "missing principal ID");
3069 exit(1);
3070 }
3071 return verify(ca_key_path, cert_principals,
3072 cert_key_id, identity_file, rr_hostname);
3073 }
3074 usage();
3075 /* NOTREACHED */
3076 }
3077
2691 if (ca_key_path != NULL) { 3078 if (ca_key_path != NULL) {
2692 if (argc < 1 && !gen_krl) { 3079 if (argc < 1 && !gen_krl) {
2693 error("Too few arguments."); 3080 error("Too few arguments.");
@@ -2739,7 +3126,10 @@ main(int argc, char **argv)
2739 do_convert_to(pw); 3126 do_convert_to(pw);
2740 if (convert_from) 3127 if (convert_from)
2741 do_convert_from(pw); 3128 do_convert_from(pw);
2742#endif 3129#else /* WITH_OPENSSL */
3130 if (convert_to || convert_from)
3131 fatal("key conversion disabled at compile time");
3132#endif /* WITH_OPENSSL */
2743 if (print_public) 3133 if (print_public)
2744 do_print_public(pw); 3134 do_print_public(pw);
2745 if (rr_hostname != NULL) { 3135 if (rr_hostname != NULL) {
@@ -2842,11 +3232,11 @@ main(int argc, char **argv)
2842 snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", 3232 snprintf(dotsshdir, sizeof dotsshdir, "%s/%s",
2843 pw->pw_dir, _PATH_SSH_USER_DIR); 3233 pw->pw_dir, _PATH_SSH_USER_DIR);
2844 if (strstr(identity_file, dotsshdir) != NULL) { 3234 if (strstr(identity_file, dotsshdir) != NULL) {
2845 if (stat(dotsshdir, &st) < 0) { 3235 if (stat(dotsshdir, &st) == -1) {
2846 if (errno != ENOENT) { 3236 if (errno != ENOENT) {
2847 error("Could not stat %s: %s", dotsshdir, 3237 error("Could not stat %s: %s", dotsshdir,
2848 strerror(errno)); 3238 strerror(errno));
2849 } else if (mkdir(dotsshdir, 0700) < 0) { 3239 } else if (mkdir(dotsshdir, 0700) == -1) {
2850 error("Could not create directory '%s': %s", 3240 error("Could not create directory '%s': %s",
2851 dotsshdir, strerror(errno)); 3241 dotsshdir, strerror(errno));
2852 } else if (!quiet) 3242 } else if (!quiet)
@@ -2854,16 +3244,8 @@ main(int argc, char **argv)
2854 } 3244 }
2855 } 3245 }
2856 /* If the file already exists, ask the user to confirm. */ 3246 /* If the file already exists, ask the user to confirm. */
2857 if (stat(identity_file, &st) >= 0) { 3247 if (!confirm_overwrite(identity_file))
2858 char yesno[3]; 3248 exit(1);
2859 printf("%s already exists.\n", identity_file);
2860 printf("Overwrite (y/n)? ");
2861 fflush(stdout);
2862 if (fgets(yesno, sizeof(yesno), stdin) == NULL)
2863 exit(1);
2864 if (yesno[0] != 'y' && yesno[0] != 'Y')
2865 exit(1);
2866 }
2867 /* Ask for a passphrase (twice). */ 3249 /* Ask for a passphrase (twice). */
2868 if (identity_passphrase) 3250 if (identity_passphrase)
2869 passphrase1 = xstrdup(identity_passphrase); 3251 passphrase1 = xstrdup(identity_passphrase);
@@ -2902,7 +3284,7 @@ passphrase_again:
2902 3284
2903 /* Save the key with the given passphrase and comment. */ 3285 /* Save the key with the given passphrase and comment. */
2904 if ((r = sshkey_save_private(private, identity_file, passphrase1, 3286 if ((r = sshkey_save_private(private, identity_file, passphrase1,
2905 comment, use_new_format, new_format_cipher, rounds)) != 0) { 3287 comment, private_key_format, openssh_format_cipher, rounds)) != 0) {
2906 error("Saving key \"%s\" failed: %s", 3288 error("Saving key \"%s\" failed: %s",
2907 identity_file, ssh_err(r)); 3289 identity_file, ssh_err(r));
2908 explicit_bzero(passphrase1, strlen(passphrase1)); 3290 explicit_bzero(passphrase1, strlen(passphrase1));