Annotation of src/usr.bin/ssh/ssh-keygen.c, Revision 1.468
1.468 ! djm 1: /* $OpenBSD: ssh-keygen.c,v 1.467 2023/04/12 08:53:54 jsg Exp $ */
1.1 deraadt 2: /*
1.13 deraadt 3: * Author: Tatu Ylonen <ylo@cs.hut.fi>
4: * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5: * All rights reserved
6: * Identity and host key generation and maintenance.
1.31 deraadt 7: *
8: * As far as I am concerned, the code I have written for this software
9: * can be used freely for any purpose. Any derived versions of this
10: * software must be clearly marked as such, and if the derived work is
11: * incompatible with the protocol description in the RFC file, it must be
12: * called by a name other than "ssh" or "Secure Shell".
1.13 deraadt 13: */
1.1 deraadt 14:
1.136 stevesk 15: #include <sys/types.h>
1.174 dtucker 16: #include <sys/socket.h>
1.136 stevesk 17: #include <sys/stat.h>
1.19 markus 18:
1.348 djm 19: #ifdef WITH_OPENSSL
1.19 markus 20: #include <openssl/evp.h>
21: #include <openssl/pem.h>
1.348 djm 22: #endif
1.145 stevesk 23:
1.347 djm 24: #include <stdint.h>
1.148 stevesk 25: #include <errno.h>
1.147 stevesk 26: #include <fcntl.h>
1.248 djm 27: #include <netdb.h>
1.145 stevesk 28: #include <pwd.h>
1.430 dtucker 29: #include <stdarg.h>
1.153 stevesk 30: #include <stdio.h>
1.152 stevesk 31: #include <stdlib.h>
1.150 stevesk 32: #include <string.h>
1.149 stevesk 33: #include <unistd.h>
1.253 deraadt 34: #include <limits.h>
1.294 djm 35: #include <locale.h>
1.1 deraadt 36:
37: #include "xmalloc.h"
1.252 djm 38: #include "sshkey.h"
1.19 markus 39: #include "authfile.h"
1.252 djm 40: #include "sshbuf.h"
1.40 markus 41: #include "pathnames.h"
1.41 markus 42: #include "log.h"
1.114 djm 43: #include "misc.h"
1.119 djm 44: #include "match.h"
45: #include "hostfile.h"
1.146 stevesk 46: #include "dns.h"
1.223 djm 47: #include "ssh.h"
1.179 djm 48: #include "ssh2.h"
1.252 djm 49: #include "ssherr.h"
1.223 djm 50: #include "atomicio.h"
51: #include "krl.h"
1.251 djm 52: #include "digest.h"
1.294 djm 53: #include "utf8.h"
1.305 djm 54: #include "authfd.h"
1.344 djm 55: #include "sshsig.h"
1.357 djm 56: #include "ssh-sk.h"
57: #include "sk-api.h" /* XXX for SSH_SK_USER_PRESENCE_REQD; remove */
1.426 dtucker 58: #include "cipher.h"
1.32 markus 59:
1.177 markus 60: #ifdef ENABLE_PKCS11
61: #include "ssh-pkcs11.h"
1.106 djm 62: #endif
1.66 markus 63:
1.273 djm 64: #ifdef WITH_OPENSSL
65: # define DEFAULT_KEY_TYPE_NAME "rsa"
66: #else
67: # define DEFAULT_KEY_TYPE_NAME "ed25519"
68: #endif
69:
1.328 dtucker 70: /*
1.329 dtucker 71: * Default number of bits in the RSA, DSA and ECDSA keys. These value can be
72: * overridden on the command line.
73: *
74: * These values, with the exception of DSA, provide security equivalent to at
75: * least 128 bits of security according to NIST Special Publication 800-57:
76: * Recommendation for Key Management Part 1 rev 4 section 5.6.1.
77: * For DSA it (and FIPS-186-4 section 4.2) specifies that the only size for
78: * which a 160bit hash is acceptable is 1kbit, and since ssh-dss specifies only
79: * SHA1 we limit the DSA key size 1k bits.
1.328 dtucker 80: */
81: #define DEFAULT_BITS 3072
1.130 markus 82: #define DEFAULT_BITS_DSA 1024
1.203 naddy 83: #define DEFAULT_BITS_ECDSA 256
1.1 deraadt 84:
1.325 djm 85: static int quiet = 0;
1.182 djm 86:
1.8 markus 87: /* Flag indicating that we just want to see the key fingerprint */
1.325 djm 88: static int print_fingerprint = 0;
89: static int print_bubblebabble = 0;
1.8 markus 90:
1.251 djm 91: /* Hash algorithm to use for fingerprints. */
1.325 djm 92: static int fingerprint_hash = SSH_FP_HASH_DEFAULT;
1.251 djm 93:
1.10 markus 94: /* The identity file name, given on the command line or entered by the user. */
1.351 deraadt 95: static char identity_file[PATH_MAX];
1.325 djm 96: static int have_identity = 0;
1.1 deraadt 97:
98: /* This is set to the passphrase if given on the command line. */
1.325 djm 99: static char *identity_passphrase = NULL;
1.1 deraadt 100:
101: /* This is set to the new passphrase if given on the command line. */
1.325 djm 102: static char *identity_new_passphrase = NULL;
1.186 djm 103:
1.179 djm 104: /* Key type when certifying */
1.325 djm 105: static u_int cert_key_type = SSH2_CERT_TYPE_USER;
1.179 djm 106:
107: /* "key ID" of signed key */
1.325 djm 108: static char *cert_key_id = NULL;
1.179 djm 109:
110: /* Comma-separated list of principal names for certifying keys */
1.325 djm 111: static char *cert_principals = NULL;
1.179 djm 112:
113: /* Validity period for certificates */
1.325 djm 114: static u_int64_t cert_valid_from = 0;
115: static u_int64_t cert_valid_to = ~0ULL;
1.179 djm 116:
1.186 djm 117: /* Certificate options */
1.371 djm 118: #define CERTOPT_X_FWD (1)
119: #define CERTOPT_AGENT_FWD (1<<1)
120: #define CERTOPT_PORT_FWD (1<<2)
121: #define CERTOPT_PTY (1<<3)
122: #define CERTOPT_USER_RC (1<<4)
123: #define CERTOPT_NO_REQUIRE_USER_PRESENCE (1<<5)
1.453 naddy 124: #define CERTOPT_REQUIRE_VERIFY (1<<6)
1.190 djm 125: #define CERTOPT_DEFAULT (CERTOPT_X_FWD|CERTOPT_AGENT_FWD| \
126: CERTOPT_PORT_FWD|CERTOPT_PTY|CERTOPT_USER_RC)
1.325 djm 127: static u_int32_t certflags_flags = CERTOPT_DEFAULT;
128: static char *certflags_command = NULL;
129: static char *certflags_src_addr = NULL;
1.179 djm 130:
1.300 djm 131: /* Arbitrary extensions specified by user */
1.415 djm 132: struct cert_ext {
1.300 djm 133: char *key;
134: char *val;
135: int crit;
136: };
1.415 djm 137: static struct cert_ext *cert_ext;
138: static size_t ncert_ext;
1.300 djm 139:
1.193 djm 140: /* Conversion to/from various formats */
141: enum {
142: FMT_RFC4716,
143: FMT_PKCS8,
144: FMT_PEM
145: } convert_format = FMT_RFC4716;
1.33 markus 146:
1.325 djm 147: static char *key_type_name = NULL;
1.19 markus 148:
1.197 djm 149: /* Load key from this PKCS#11 provider */
1.325 djm 150: static char *pkcs11provider = NULL;
1.193 djm 151:
1.357 djm 152: /* FIDO/U2F provider to use */
153: static char *sk_provider = NULL;
154:
1.336 djm 155: /* Format for writing private keys */
156: static int private_key_format = SSHKEY_PRIVATE_OPENSSH;
1.237 markus 157:
158: /* Cipher for new-format private keys */
1.336 djm 159: static char *openssh_format_cipher = NULL;
1.237 markus 160:
1.376 djm 161: /* Number of KDF rounds to derive new format keys. */
1.325 djm 162: static int rounds = 0;
1.237 markus 163:
1.10 markus 164: /* argv0 */
165: extern char *__progname;
1.1 deraadt 166:
1.325 djm 167: static char hostname[NI_MAXHOST];
1.19 markus 168:
1.274 djm 169: #ifdef WITH_OPENSSL
1.115 djm 170: /* moduli.c */
1.124 avsm 171: int gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *);
1.215 dtucker 172: int prime_test(FILE *, FILE *, u_int32_t, u_int32_t, char *, unsigned long,
173: unsigned long);
1.274 djm 174: #endif
1.115 djm 175:
1.63 itojun 176: static void
1.255 djm 177: type_bits_valid(int type, const char *name, u_int32_t *bitsp)
1.206 stevesk 178: {
1.269 djm 179: if (type == KEY_UNSPEC)
180: fatal("unknown key type %s", key_type_name);
1.209 djm 181: if (*bitsp == 0) {
1.271 djm 182: #ifdef WITH_OPENSSL
1.423 djm 183: int nid;
1.339 naddy 184:
185: switch(type) {
186: case KEY_DSA:
1.209 djm 187: *bitsp = DEFAULT_BITS_DSA;
1.339 naddy 188: break;
189: case KEY_ECDSA:
1.255 djm 190: if (name != NULL &&
191: (nid = sshkey_ecdsa_nid_from_name(name)) > 0)
192: *bitsp = sshkey_curve_nid_to_bits(nid);
193: if (*bitsp == 0)
194: *bitsp = DEFAULT_BITS_ECDSA;
1.339 naddy 195: break;
196: case KEY_RSA:
197: *bitsp = DEFAULT_BITS;
198: break;
199: }
1.271 djm 200: #endif
1.206 stevesk 201: }
1.271 djm 202: #ifdef WITH_OPENSSL
1.303 djm 203: switch (type) {
204: case KEY_DSA:
205: if (*bitsp != 1024)
206: fatal("Invalid DSA key length: must be 1024 bits");
207: break;
208: case KEY_RSA:
209: if (*bitsp < SSH_RSA_MINIMUM_MODULUS_SIZE)
210: fatal("Invalid RSA key length: minimum is %d bits",
211: SSH_RSA_MINIMUM_MODULUS_SIZE);
1.339 naddy 212: else if (*bitsp > OPENSSL_RSA_MAX_MODULUS_BITS)
213: fatal("Invalid RSA key length: maximum is %d bits",
214: OPENSSL_RSA_MAX_MODULUS_BITS);
1.303 djm 215: break;
216: case KEY_ECDSA:
217: if (sshkey_ecdsa_bits_to_nid(*bitsp) == -1)
218: fatal("Invalid ECDSA key length: valid lengths are "
219: "256, 384 or 521 bits");
220: }
1.246 markus 221: #endif
1.206 stevesk 222: }
223:
1.343 djm 224: /*
225: * Checks whether a file exists and, if so, asks the user whether they wish
226: * to overwrite it.
227: * Returns nonzero if the file does not already exist or if the user agrees to
228: * overwrite, or zero otherwise.
229: */
230: static int
231: confirm_overwrite(const char *filename)
232: {
233: char yesno[3];
234: struct stat st;
235:
236: if (stat(filename, &st) != 0)
237: return 1;
238: printf("%s already exists.\n", filename);
239: printf("Overwrite (y/n)? ");
240: fflush(stdout);
241: if (fgets(yesno, sizeof(yesno), stdin) == NULL)
242: return 0;
243: if (yesno[0] != 'y' && yesno[0] != 'Y')
244: return 0;
245: return 1;
246: }
247:
1.206 stevesk 248: static void
1.10 markus 249: ask_filename(struct passwd *pw, const char *prompt)
1.1 deraadt 250: {
1.12 markus 251: char buf[1024];
1.35 markus 252: char *name = NULL;
253:
1.92 stevesk 254: if (key_type_name == NULL)
1.40 markus 255: name = _PATH_SSH_CLIENT_ID_RSA;
1.140 deraadt 256: else {
1.252 djm 257: switch (sshkey_type_from_name(key_type_name)) {
1.186 djm 258: case KEY_DSA_CERT:
1.92 stevesk 259: case KEY_DSA:
260: name = _PATH_SSH_CLIENT_ID_DSA;
261: break;
1.200 djm 262: case KEY_ECDSA_CERT:
263: case KEY_ECDSA:
264: name = _PATH_SSH_CLIENT_ID_ECDSA;
265: break;
1.357 djm 266: case KEY_ECDSA_SK_CERT:
267: case KEY_ECDSA_SK:
268: name = _PATH_SSH_CLIENT_ID_ECDSA_SK;
269: break;
1.186 djm 270: case KEY_RSA_CERT:
1.92 stevesk 271: case KEY_RSA:
272: name = _PATH_SSH_CLIENT_ID_RSA;
273: break;
1.238 markus 274: case KEY_ED25519:
275: case KEY_ED25519_CERT:
276: name = _PATH_SSH_CLIENT_ID_ED25519;
277: break;
1.362 markus 278: case KEY_ED25519_SK:
279: case KEY_ED25519_SK_CERT:
280: name = _PATH_SSH_CLIENT_ID_ED25519_SK;
281: break;
1.313 markus 282: case KEY_XMSS:
283: case KEY_XMSS_CERT:
284: name = _PATH_SSH_CLIENT_ID_XMSS;
285: break;
1.92 stevesk 286: default:
1.269 djm 287: fatal("bad key type");
1.92 stevesk 288: }
1.140 deraadt 289: }
1.269 djm 290: snprintf(identity_file, sizeof(identity_file),
291: "%s/%s", pw->pw_dir, name);
292: printf("%s (%s): ", prompt, identity_file);
293: fflush(stdout);
1.12 markus 294: if (fgets(buf, sizeof(buf), stdin) == NULL)
295: exit(1);
1.162 gilles 296: buf[strcspn(buf, "\n")] = '\0';
1.12 markus 297: if (strcmp(buf, "") != 0)
298: strlcpy(identity_file, buf, sizeof(identity_file));
299: have_identity = 1;
1.7 markus 300: }
301:
1.252 djm 302: static struct sshkey *
1.342 djm 303: load_identity(const char *filename, char **commentp)
1.19 markus 304: {
1.52 markus 305: char *pass;
1.252 djm 306: struct sshkey *prv;
307: int r;
1.52 markus 308:
1.341 djm 309: if (commentp != NULL)
310: *commentp = NULL;
311: if ((r = sshkey_load_private(filename, "", &prv, commentp)) == 0)
1.252 djm 312: return prv;
313: if (r != SSH_ERR_KEY_WRONG_PASSPHRASE)
1.421 djm 314: fatal_r(r, "Load key \"%s\"", filename);
1.252 djm 315: if (identity_passphrase)
316: pass = xstrdup(identity_passphrase);
317: else
318: pass = read_passphrase("Enter passphrase: ", RP_ALLOW_STDIN);
1.341 djm 319: r = sshkey_load_private(filename, pass, &prv, commentp);
1.399 jsg 320: freezero(pass, strlen(pass));
1.252 djm 321: if (r != 0)
1.421 djm 322: fatal_r(r, "Load key \"%s\"", filename);
1.52 markus 323: return prv;
1.19 markus 324: }
325:
1.32 markus 326: #define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
1.100 deraadt 327: #define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----"
1.32 markus 328: #define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
1.42 stevesk 329: #define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb
1.19 markus 330:
1.246 markus 331: #ifdef WITH_OPENSSL
1.63 itojun 332: static void
1.252 djm 333: do_convert_to_ssh2(struct passwd *pw, struct sshkey *k)
1.19 markus 334: {
1.337 djm 335: struct sshbuf *b;
336: char comment[61], *b64;
1.252 djm 337: int r;
1.19 markus 338:
1.337 djm 339: if ((b = sshbuf_new()) == NULL)
1.421 djm 340: fatal_f("sshbuf_new failed");
1.337 djm 341: if ((r = sshkey_putb(k, b)) != 0)
1.421 djm 342: fatal_fr(r, "put key");
1.337 djm 343: if ((b64 = sshbuf_dtob64_string(b, 1)) == NULL)
1.421 djm 344: fatal_f("sshbuf_dtob64_string failed");
1.337 djm 345:
1.176 djm 346: /* Comment + surrounds must fit into 72 chars (RFC 4716 sec 3.3) */
347: snprintf(comment, sizeof(comment),
348: "%u-bit %s, converted by %s@%s from OpenSSH",
1.252 djm 349: sshkey_size(k), sshkey_type(k),
1.19 markus 350: pw->pw_name, hostname);
1.176 djm 351:
1.337 djm 352: sshkey_free(k);
353: sshbuf_free(b);
354:
1.176 djm 355: fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
1.337 djm 356: fprintf(stdout, "Comment: \"%s\"\n%s", comment, b64);
1.32 markus 357: fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
1.337 djm 358: free(b64);
1.19 markus 359: exit(0);
360: }
361:
1.63 itojun 362: static void
1.252 djm 363: do_convert_to_pkcs8(struct sshkey *k)
1.193 djm 364: {
1.252 djm 365: switch (sshkey_type_plain(k->type)) {
1.193 djm 366: case KEY_RSA:
367: if (!PEM_write_RSA_PUBKEY(stdout, k->rsa))
368: fatal("PEM_write_RSA_PUBKEY failed");
369: break;
370: case KEY_DSA:
371: if (!PEM_write_DSA_PUBKEY(stdout, k->dsa))
372: fatal("PEM_write_DSA_PUBKEY failed");
373: break;
1.200 djm 374: case KEY_ECDSA:
375: if (!PEM_write_EC_PUBKEY(stdout, k->ecdsa))
376: fatal("PEM_write_EC_PUBKEY failed");
377: break;
1.193 djm 378: default:
1.421 djm 379: fatal_f("unsupported key type %s", sshkey_type(k));
1.193 djm 380: }
381: exit(0);
382: }
383:
384: static void
1.252 djm 385: do_convert_to_pem(struct sshkey *k)
1.193 djm 386: {
1.252 djm 387: switch (sshkey_type_plain(k->type)) {
1.193 djm 388: case KEY_RSA:
389: if (!PEM_write_RSAPublicKey(stdout, k->rsa))
390: fatal("PEM_write_RSAPublicKey failed");
1.389 djm 391: break;
392: case KEY_DSA:
393: if (!PEM_write_DSA_PUBKEY(stdout, k->dsa))
394: fatal("PEM_write_DSA_PUBKEY failed");
395: break;
396: case KEY_ECDSA:
397: if (!PEM_write_EC_PUBKEY(stdout, k->ecdsa))
398: fatal("PEM_write_EC_PUBKEY failed");
1.193 djm 399: break;
400: default:
1.421 djm 401: fatal_f("unsupported key type %s", sshkey_type(k));
1.193 djm 402: }
403: exit(0);
404: }
405:
406: static void
407: do_convert_to(struct passwd *pw)
408: {
1.252 djm 409: struct sshkey *k;
1.193 djm 410: struct stat st;
1.252 djm 411: int r;
1.193 djm 412:
413: if (!have_identity)
414: ask_filename(pw, "Enter file in which the key is");
1.333 deraadt 415: if (stat(identity_file, &st) == -1)
1.193 djm 416: fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
1.252 djm 417: if ((r = sshkey_load_public(identity_file, &k, NULL)) != 0)
1.341 djm 418: k = load_identity(identity_file, NULL);
1.193 djm 419: switch (convert_format) {
420: case FMT_RFC4716:
421: do_convert_to_ssh2(pw, k);
422: break;
423: case FMT_PKCS8:
424: do_convert_to_pkcs8(k);
425: break;
426: case FMT_PEM:
427: do_convert_to_pem(k);
428: break;
429: default:
1.421 djm 430: fatal_f("unknown key format %d", convert_format);
1.193 djm 431: }
432: exit(0);
433: }
434:
1.252 djm 435: /*
436: * This is almost exactly the bignum1 encoding, but with 32 bit for length
437: * instead of 16.
438: */
1.193 djm 439: static void
1.252 djm 440: buffer_get_bignum_bits(struct sshbuf *b, BIGNUM *value)
1.32 markus 441: {
1.252 djm 442: u_int bytes, bignum_bits;
443: int r;
1.53 markus 444:
1.252 djm 445: if ((r = sshbuf_get_u32(b, &bignum_bits)) != 0)
1.421 djm 446: fatal_fr(r, "parse");
1.252 djm 447: bytes = (bignum_bits + 7) / 8;
448: if (sshbuf_len(b) < bytes)
1.421 djm 449: fatal_f("input buffer too small: need %d have %zu",
450: bytes, sshbuf_len(b));
1.252 djm 451: if (BN_bin2bn(sshbuf_ptr(b), bytes, value) == NULL)
1.421 djm 452: fatal_f("BN_bin2bn failed");
1.252 djm 453: if ((r = sshbuf_consume(b, bytes)) != 0)
1.421 djm 454: fatal_fr(r, "consume");
1.32 markus 455: }
456:
1.252 djm 457: static struct sshkey *
1.337 djm 458: do_convert_private_ssh2(struct sshbuf *b)
1.32 markus 459: {
1.252 djm 460: struct sshkey *key = NULL;
1.64 markus 461: char *type, *cipher;
1.466 djm 462: const char *alg = NULL;
1.252 djm 463: u_char e1, e2, e3, *sig = NULL, data[] = "abcde12345";
464: int r, rlen, ktype;
465: u_int magic, i1, i2, i3, i4;
466: size_t slen;
1.62 markus 467: u_long e;
1.321 djm 468: BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL;
469: BIGNUM *dsa_pub_key = NULL, *dsa_priv_key = NULL;
470: BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL;
471: BIGNUM *rsa_p = NULL, *rsa_q = NULL, *rsa_iqmp = NULL;
1.337 djm 472:
1.252 djm 473: if ((r = sshbuf_get_u32(b, &magic)) != 0)
1.421 djm 474: fatal_fr(r, "parse magic");
1.32 markus 475:
476: if (magic != SSH_COM_PRIVATE_KEY_MAGIC) {
1.252 djm 477: error("bad magic 0x%x != 0x%x", magic,
478: SSH_COM_PRIVATE_KEY_MAGIC);
1.32 markus 479: return NULL;
480: }
1.252 djm 481: if ((r = sshbuf_get_u32(b, &i1)) != 0 ||
482: (r = sshbuf_get_cstring(b, &type, NULL)) != 0 ||
483: (r = sshbuf_get_cstring(b, &cipher, NULL)) != 0 ||
484: (r = sshbuf_get_u32(b, &i2)) != 0 ||
485: (r = sshbuf_get_u32(b, &i3)) != 0 ||
486: (r = sshbuf_get_u32(b, &i4)) != 0)
1.421 djm 487: fatal_fr(r, "parse");
1.158 stevesk 488: debug("ignore (%d %d %d %d)", i1, i2, i3, i4);
1.32 markus 489: if (strcmp(cipher, "none") != 0) {
490: error("unsupported cipher %s", cipher);
1.227 djm 491: free(cipher);
492: free(type);
1.32 markus 493: return NULL;
494: }
1.227 djm 495: free(cipher);
1.32 markus 496:
1.53 markus 497: if (strstr(type, "dsa")) {
498: ktype = KEY_DSA;
499: } else if (strstr(type, "rsa")) {
500: ktype = KEY_RSA;
501: } else {
1.227 djm 502: free(type);
1.32 markus 503: return NULL;
504: }
1.322 djm 505: if ((key = sshkey_new(ktype)) == NULL)
506: fatal("sshkey_new failed");
1.227 djm 507: free(type);
1.53 markus 508:
509: switch (key->type) {
510: case KEY_DSA:
1.321 djm 511: if ((dsa_p = BN_new()) == NULL ||
512: (dsa_q = BN_new()) == NULL ||
513: (dsa_g = BN_new()) == NULL ||
514: (dsa_pub_key = BN_new()) == NULL ||
515: (dsa_priv_key = BN_new()) == NULL)
1.421 djm 516: fatal_f("BN_new");
1.321 djm 517: buffer_get_bignum_bits(b, dsa_p);
518: buffer_get_bignum_bits(b, dsa_g);
519: buffer_get_bignum_bits(b, dsa_q);
520: buffer_get_bignum_bits(b, dsa_pub_key);
521: buffer_get_bignum_bits(b, dsa_priv_key);
522: if (!DSA_set0_pqg(key->dsa, dsa_p, dsa_q, dsa_g))
1.421 djm 523: fatal_f("DSA_set0_pqg failed");
1.321 djm 524: dsa_p = dsa_q = dsa_g = NULL; /* transferred */
525: if (!DSA_set0_key(key->dsa, dsa_pub_key, dsa_priv_key))
1.421 djm 526: fatal_f("DSA_set0_key failed");
1.321 djm 527: dsa_pub_key = dsa_priv_key = NULL; /* transferred */
1.53 markus 528: break;
529: case KEY_RSA:
1.252 djm 530: if ((r = sshbuf_get_u8(b, &e1)) != 0 ||
531: (e1 < 30 && (r = sshbuf_get_u8(b, &e2)) != 0) ||
532: (e1 < 30 && (r = sshbuf_get_u8(b, &e3)) != 0))
1.421 djm 533: fatal_fr(r, "parse RSA");
1.252 djm 534: e = e1;
1.62 markus 535: debug("e %lx", e);
536: if (e < 30) {
537: e <<= 8;
1.252 djm 538: e += e2;
1.62 markus 539: debug("e %lx", e);
540: e <<= 8;
1.252 djm 541: e += e3;
1.62 markus 542: debug("e %lx", e);
543: }
1.321 djm 544: if ((rsa_e = BN_new()) == NULL)
1.421 djm 545: fatal_f("BN_new");
1.321 djm 546: if (!BN_set_word(rsa_e, e)) {
547: BN_clear_free(rsa_e);
1.252 djm 548: sshkey_free(key);
1.53 markus 549: return NULL;
550: }
1.321 djm 551: if ((rsa_n = BN_new()) == NULL ||
552: (rsa_d = BN_new()) == NULL ||
553: (rsa_p = BN_new()) == NULL ||
554: (rsa_q = BN_new()) == NULL ||
555: (rsa_iqmp = BN_new()) == NULL)
1.421 djm 556: fatal_f("BN_new");
1.321 djm 557: buffer_get_bignum_bits(b, rsa_d);
558: buffer_get_bignum_bits(b, rsa_n);
559: buffer_get_bignum_bits(b, rsa_iqmp);
560: buffer_get_bignum_bits(b, rsa_q);
561: buffer_get_bignum_bits(b, rsa_p);
562: if (!RSA_set0_key(key->rsa, rsa_n, rsa_e, rsa_d))
1.421 djm 563: fatal_f("RSA_set0_key failed");
1.321 djm 564: rsa_n = rsa_e = rsa_d = NULL; /* transferred */
565: if (!RSA_set0_factors(key->rsa, rsa_p, rsa_q))
1.421 djm 566: fatal_f("RSA_set0_factors failed");
1.321 djm 567: rsa_p = rsa_q = NULL; /* transferred */
568: if ((r = ssh_rsa_complete_crt_parameters(key, rsa_iqmp)) != 0)
1.421 djm 569: fatal_fr(r, "generate RSA parameters");
1.321 djm 570: BN_clear_free(rsa_iqmp);
1.466 djm 571: alg = "rsa-sha2-256";
1.53 markus 572: break;
573: }
1.252 djm 574: rlen = sshbuf_len(b);
1.85 deraadt 575: if (rlen != 0)
1.421 djm 576: error_f("remaining bytes in key blob %d", rlen);
1.64 markus 577:
578: /* try the key */
1.455 djm 579: if ((r = sshkey_sign(key, &sig, &slen, data, sizeof(data),
1.466 djm 580: alg, NULL, NULL, 0)) != 0)
1.455 djm 581: error_fr(r, "signing with converted key failed");
582: else if ((r = sshkey_verify(key, sig, slen, data, sizeof(data),
1.466 djm 583: alg, 0, NULL)) != 0)
1.455 djm 584: error_fr(r, "verification with converted key failed");
585: if (r != 0) {
1.252 djm 586: sshkey_free(key);
587: free(sig);
588: return NULL;
589: }
1.227 djm 590: free(sig);
1.32 markus 591: return key;
592: }
593:
1.137 dtucker 594: static int
595: get_line(FILE *fp, char *line, size_t len)
596: {
597: int c;
598: size_t pos = 0;
599:
600: line[0] = '\0';
601: while ((c = fgetc(fp)) != EOF) {
1.269 djm 602: if (pos >= len - 1)
603: fatal("input line too long.");
1.140 deraadt 604: switch (c) {
1.137 dtucker 605: case '\r':
606: c = fgetc(fp);
1.269 djm 607: if (c != EOF && c != '\n' && ungetc(c, fp) == EOF)
608: fatal("unget: %s", strerror(errno));
1.137 dtucker 609: return pos;
610: case '\n':
611: return pos;
612: }
613: line[pos++] = c;
614: line[pos] = '\0';
615: }
1.157 stevesk 616: /* We reached EOF */
617: return -1;
1.137 dtucker 618: }
619:
1.63 itojun 620: static void
1.252 djm 621: do_convert_from_ssh2(struct passwd *pw, struct sshkey **k, int *private)
1.19 markus 622: {
1.252 djm 623: int r, blen, escaped = 0;
1.98 markus 624: u_int len;
1.137 dtucker 625: char line[1024];
1.337 djm 626: struct sshbuf *buf;
1.19 markus 627: char encoded[8096];
628: FILE *fp;
629:
1.337 djm 630: if ((buf = sshbuf_new()) == NULL)
631: fatal("sshbuf_new failed");
1.191 djm 632: if ((fp = fopen(identity_file, "r")) == NULL)
633: fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
1.19 markus 634: encoded[0] = '\0';
1.137 dtucker 635: while ((blen = get_line(fp, line, sizeof(line))) != -1) {
1.228 djm 636: if (blen > 0 && line[blen - 1] == '\\')
1.25 markus 637: escaped++;
1.19 markus 638: if (strncmp(line, "----", 4) == 0 ||
639: strstr(line, ": ") != NULL) {
1.32 markus 640: if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL)
1.193 djm 641: *private = 1;
1.64 markus 642: if (strstr(line, " END ") != NULL) {
643: break;
644: }
1.60 markus 645: /* fprintf(stderr, "ignore: %s", line); */
1.19 markus 646: continue;
647: }
1.25 markus 648: if (escaped) {
649: escaped--;
1.60 markus 650: /* fprintf(stderr, "escaped: %s", line); */
1.25 markus 651: continue;
1.19 markus 652: }
653: strlcat(encoded, line, sizeof(encoded));
654: }
1.98 markus 655: len = strlen(encoded);
656: if (((len % 4) == 3) &&
657: (encoded[len-1] == '=') &&
658: (encoded[len-2] == '=') &&
659: (encoded[len-3] == '='))
660: encoded[len-3] = '\0';
1.337 djm 661: if ((r = sshbuf_b64tod(buf, encoded)) != 0)
1.421 djm 662: fatal_fr(r, "base64 decode");
1.408 djm 663: if (*private) {
664: if ((*k = do_convert_private_ssh2(buf)) == NULL)
1.421 djm 665: fatal_f("private key conversion failed");
1.408 djm 666: } else if ((r = sshkey_fromb(buf, k)) != 0)
1.421 djm 667: fatal_fr(r, "parse key");
1.356 djm 668: sshbuf_free(buf);
1.193 djm 669: fclose(fp);
670: }
671:
672: static void
1.252 djm 673: do_convert_from_pkcs8(struct sshkey **k, int *private)
1.193 djm 674: {
675: EVP_PKEY *pubkey;
676: FILE *fp;
677:
678: if ((fp = fopen(identity_file, "r")) == NULL)
679: fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
680: if ((pubkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
1.421 djm 681: fatal_f("%s is not a recognised public key format",
1.193 djm 682: identity_file);
683: }
684: fclose(fp);
1.321 djm 685: switch (EVP_PKEY_base_id(pubkey)) {
1.193 djm 686: case EVP_PKEY_RSA:
1.252 djm 687: if ((*k = sshkey_new(KEY_UNSPEC)) == NULL)
688: fatal("sshkey_new failed");
1.193 djm 689: (*k)->type = KEY_RSA;
690: (*k)->rsa = EVP_PKEY_get1_RSA(pubkey);
691: break;
692: case EVP_PKEY_DSA:
1.252 djm 693: if ((*k = sshkey_new(KEY_UNSPEC)) == NULL)
694: fatal("sshkey_new failed");
1.193 djm 695: (*k)->type = KEY_DSA;
696: (*k)->dsa = EVP_PKEY_get1_DSA(pubkey);
697: break;
1.200 djm 698: case EVP_PKEY_EC:
1.252 djm 699: if ((*k = sshkey_new(KEY_UNSPEC)) == NULL)
700: fatal("sshkey_new failed");
1.200 djm 701: (*k)->type = KEY_ECDSA;
702: (*k)->ecdsa = EVP_PKEY_get1_EC_KEY(pubkey);
1.252 djm 703: (*k)->ecdsa_nid = sshkey_ecdsa_key_to_nid((*k)->ecdsa);
1.200 djm 704: break;
1.193 djm 705: default:
1.421 djm 706: fatal_f("unsupported pubkey type %d",
1.321 djm 707: EVP_PKEY_base_id(pubkey));
1.193 djm 708: }
709: EVP_PKEY_free(pubkey);
710: return;
711: }
712:
713: static void
1.252 djm 714: do_convert_from_pem(struct sshkey **k, int *private)
1.193 djm 715: {
716: FILE *fp;
717: RSA *rsa;
718:
719: if ((fp = fopen(identity_file, "r")) == NULL)
720: fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
721: if ((rsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL)) != NULL) {
1.252 djm 722: if ((*k = sshkey_new(KEY_UNSPEC)) == NULL)
723: fatal("sshkey_new failed");
1.193 djm 724: (*k)->type = KEY_RSA;
725: (*k)->rsa = rsa;
726: fclose(fp);
727: return;
728: }
1.421 djm 729: fatal_f("unrecognised raw private key format");
1.193 djm 730: }
731:
732: static void
733: do_convert_from(struct passwd *pw)
734: {
1.252 djm 735: struct sshkey *k = NULL;
736: int r, private = 0, ok = 0;
1.193 djm 737: struct stat st;
738:
739: if (!have_identity)
740: ask_filename(pw, "Enter file in which the key is");
1.333 deraadt 741: if (stat(identity_file, &st) == -1)
1.193 djm 742: fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
743:
744: switch (convert_format) {
745: case FMT_RFC4716:
746: do_convert_from_ssh2(pw, &k, &private);
747: break;
748: case FMT_PKCS8:
749: do_convert_from_pkcs8(&k, &private);
750: break;
751: case FMT_PEM:
752: do_convert_from_pem(&k, &private);
753: break;
754: default:
1.421 djm 755: fatal_f("unknown key format %d", convert_format);
1.193 djm 756: }
757:
1.260 djm 758: if (!private) {
1.252 djm 759: if ((r = sshkey_write(k, stdout)) == 0)
760: ok = 1;
1.193 djm 761: if (ok)
762: fprintf(stdout, "\n");
1.260 djm 763: } else {
1.193 djm 764: switch (k->type) {
765: case KEY_DSA:
766: ok = PEM_write_DSAPrivateKey(stdout, k->dsa, NULL,
767: NULL, 0, NULL, NULL);
768: break;
1.200 djm 769: case KEY_ECDSA:
770: ok = PEM_write_ECPrivateKey(stdout, k->ecdsa, NULL,
771: NULL, 0, NULL, NULL);
772: break;
1.193 djm 773: case KEY_RSA:
774: ok = PEM_write_RSAPrivateKey(stdout, k->rsa, NULL,
775: NULL, 0, NULL, NULL);
776: break;
777: default:
1.421 djm 778: fatal_f("unsupported key type %s", sshkey_type(k));
1.193 djm 779: }
780: }
781:
1.269 djm 782: if (!ok)
783: fatal("key write failed");
1.252 djm 784: sshkey_free(k);
1.19 markus 785: exit(0);
786: }
1.246 markus 787: #endif
1.19 markus 788:
1.63 itojun 789: static void
1.19 markus 790: do_print_public(struct passwd *pw)
791: {
1.252 djm 792: struct sshkey *prv;
1.19 markus 793: struct stat st;
1.252 djm 794: int r;
1.341 djm 795: char *comment = NULL;
1.19 markus 796:
797: if (!have_identity)
798: ask_filename(pw, "Enter file in which the key is");
1.333 deraadt 799: if (stat(identity_file, &st) == -1)
1.269 djm 800: fatal("%s: %s", identity_file, strerror(errno));
1.341 djm 801: prv = load_identity(identity_file, &comment);
1.252 djm 802: if ((r = sshkey_write(prv, stdout)) != 0)
1.421 djm 803: fatal_fr(r, "write key");
1.341 djm 804: if (comment != NULL && *comment != '\0')
805: fprintf(stdout, " %s", comment);
1.19 markus 806: fprintf(stdout, "\n");
1.419 djm 807: if (sshkey_is_sk(prv)) {
808: debug("sk_application: \"%s\", sk_flags 0x%02x",
809: prv->sk_application, prv->sk_flags);
810: }
811: sshkey_free(prv);
1.341 djm 812: free(comment);
1.19 markus 813: exit(0);
814: }
815:
1.66 markus 816: static void
1.197 djm 817: do_download(struct passwd *pw)
1.75 markus 818: {
1.177 markus 819: #ifdef ENABLE_PKCS11
1.252 djm 820: struct sshkey **keys = NULL;
1.177 markus 821: int i, nkeys;
1.252 djm 822: enum sshkey_fp_rep rep;
1.251 djm 823: int fptype;
1.392 djm 824: char *fp, *ra, **comments = NULL;
1.222 djm 825:
1.251 djm 826: fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash;
827: rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT;
1.75 markus 828:
1.327 benno 829: pkcs11_init(1);
1.392 djm 830: nkeys = pkcs11_add_provider(pkcs11provider, NULL, &keys, &comments);
1.177 markus 831: if (nkeys <= 0)
832: fatal("cannot read public key from pkcs11");
833: for (i = 0; i < nkeys; i++) {
1.221 djm 834: if (print_fingerprint) {
1.252 djm 835: fp = sshkey_fingerprint(keys[i], fptype, rep);
836: ra = sshkey_fingerprint(keys[i], fingerprint_hash,
1.221 djm 837: SSH_FP_RANDOMART);
1.259 djm 838: if (fp == NULL || ra == NULL)
1.421 djm 839: fatal_f("sshkey_fingerprint fail");
1.252 djm 840: printf("%u %s %s (PKCS11 key)\n", sshkey_size(keys[i]),
841: fp, sshkey_type(keys[i]));
1.325 djm 842: if (log_level_get() >= SYSLOG_LEVEL_VERBOSE)
1.221 djm 843: printf("%s\n", ra);
1.227 djm 844: free(ra);
845: free(fp);
1.221 djm 846: } else {
1.252 djm 847: (void) sshkey_write(keys[i], stdout); /* XXX check */
1.392 djm 848: fprintf(stdout, "%s%s\n",
849: *(comments[i]) == '\0' ? "" : " ", comments[i]);
1.221 djm 850: }
1.392 djm 851: free(comments[i]);
1.252 djm 852: sshkey_free(keys[i]);
1.97 markus 853: }
1.392 djm 854: free(comments);
1.227 djm 855: free(keys);
1.177 markus 856: pkcs11_terminate();
1.75 markus 857: exit(0);
1.177 markus 858: #else
859: fatal("no pkcs11 support");
860: #endif /* ENABLE_PKCS11 */
1.75 markus 861: }
1.66 markus 862:
1.279 djm 863: static struct sshkey *
864: try_read_key(char **cpp)
865: {
866: struct sshkey *ret;
867: int r;
868:
869: if ((ret = sshkey_new(KEY_UNSPEC)) == NULL)
870: fatal("sshkey_new failed");
871: if ((r = sshkey_read(ret, cpp)) == 0)
872: return ret;
873: /* Not a key */
874: sshkey_free(ret);
875: return NULL;
876: }
877:
1.63 itojun 878: static void
1.279 djm 879: fingerprint_one_key(const struct sshkey *public, const char *comment)
1.8 markus 880: {
1.279 djm 881: char *fp = NULL, *ra = NULL;
1.252 djm 882: enum sshkey_fp_rep rep;
1.251 djm 883: int fptype;
1.12 markus 884:
1.251 djm 885: fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash;
886: rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT;
1.279 djm 887: fp = sshkey_fingerprint(public, fptype, rep);
888: ra = sshkey_fingerprint(public, fingerprint_hash, SSH_FP_RANDOMART);
889: if (fp == NULL || ra == NULL)
1.421 djm 890: fatal_f("sshkey_fingerprint failed");
1.294 djm 891: mprintf("%u %s %s (%s)\n", sshkey_size(public), fp,
1.279 djm 892: comment ? comment : "no comment", sshkey_type(public));
1.325 djm 893: if (log_level_get() >= SYSLOG_LEVEL_VERBOSE)
1.279 djm 894: printf("%s\n", ra);
895: free(ra);
896: free(fp);
897: }
898:
899: static void
900: fingerprint_private(const char *path)
901: {
902: struct stat st;
903: char *comment = NULL;
1.407 djm 904: struct sshkey *privkey = NULL, *pubkey = NULL;
1.279 djm 905: int r;
906:
1.333 deraadt 907: if (stat(identity_file, &st) == -1)
1.279 djm 908: fatal("%s: %s", path, strerror(errno));
1.407 djm 909: if ((r = sshkey_load_public(path, &pubkey, &comment)) != 0)
1.421 djm 910: debug_r(r, "load public \"%s\"", path);
1.407 djm 911: if (pubkey == NULL || comment == NULL || *comment == '\0') {
912: free(comment);
913: if ((r = sshkey_load_private(path, NULL,
914: &privkey, &comment)) != 0)
1.421 djm 915: debug_r(r, "load private \"%s\"", path);
1.407 djm 916: }
917: if (pubkey == NULL && privkey == NULL)
918: fatal("%s is not a key file.", path);
919:
920: fingerprint_one_key(pubkey == NULL ? privkey : pubkey, comment);
921: sshkey_free(pubkey);
922: sshkey_free(privkey);
1.279 djm 923: free(comment);
924: }
925:
926: static void
927: do_fingerprint(struct passwd *pw)
928: {
929: FILE *f;
930: struct sshkey *public = NULL;
1.317 markus 931: char *comment = NULL, *cp, *ep, *line = NULL;
932: size_t linesize = 0;
1.279 djm 933: int i, invalid = 1;
934: const char *path;
1.289 djm 935: u_long lnum = 0;
1.279 djm 936:
1.12 markus 937: if (!have_identity)
938: ask_filename(pw, "Enter file in which the key is");
1.279 djm 939: path = identity_file;
1.15 markus 940:
1.279 djm 941: if (strcmp(identity_file, "-") == 0) {
942: f = stdin;
943: path = "(stdin)";
944: } else if ((f = fopen(path, "r")) == NULL)
945: fatal("%s: %s: %s", __progname, path, strerror(errno));
946:
1.317 markus 947: while (getline(&line, &linesize, f) != -1) {
948: lnum++;
1.279 djm 949: cp = line;
950: cp[strcspn(cp, "\n")] = '\0';
951: /* Trim leading space and comments */
952: cp = line + strspn(line, " \t");
953: if (*cp == '#' || *cp == '\0')
954: continue;
1.191 djm 955:
1.279 djm 956: /*
957: * Input may be plain keys, private keys, authorized_keys
958: * or known_hosts.
959: */
960:
961: /*
962: * Try private keys first. Assume a key is private if
963: * "SSH PRIVATE KEY" appears on the first line and we're
964: * not reading from stdin (XXX support private keys on stdin).
965: */
966: if (lnum == 1 && strcmp(identity_file, "-") != 0 &&
1.280 djm 967: strstr(cp, "PRIVATE KEY") != NULL) {
1.317 markus 968: free(line);
1.279 djm 969: fclose(f);
970: fingerprint_private(path);
971: exit(0);
972: }
973:
974: /*
975: * If it's not a private key, then this must be prepared to
976: * accept a public key prefixed with a hostname or options.
977: * Try a bare key first, otherwise skip the leading stuff.
978: */
1.468 ! djm 979: comment = NULL;
1.279 djm 980: if ((public = try_read_key(&cp)) == NULL) {
981: i = strtol(cp, &ep, 10);
982: if (i == 0 || ep == NULL ||
983: (*ep != ' ' && *ep != '\t')) {
984: int quoted = 0;
985:
986: comment = cp;
987: for (; *cp && (quoted || (*cp != ' ' &&
988: *cp != '\t')); cp++) {
989: if (*cp == '\\' && cp[1] == '"')
990: cp++; /* Skip both */
991: else if (*cp == '"')
992: quoted = !quoted;
993: }
994: if (!*cp)
995: continue;
996: *cp++ = '\0';
997: }
1.191 djm 998: }
1.279 djm 999: /* Retry after parsing leading hostname/key options */
1000: if (public == NULL && (public = try_read_key(&cp)) == NULL) {
1.289 djm 1001: debug("%s:%lu: not a public key", path, lnum);
1.191 djm 1002: continue;
1003: }
1004:
1.279 djm 1005: /* Find trailing comment, if any */
1006: for (; *cp == ' ' || *cp == '\t'; cp++)
1.191 djm 1007: ;
1.279 djm 1008: if (*cp != '\0' && *cp != '#')
1.191 djm 1009: comment = cp;
1.279 djm 1010:
1011: fingerprint_one_key(public, comment);
1.252 djm 1012: sshkey_free(public);
1.279 djm 1013: invalid = 0; /* One good key in the file is sufficient */
1.15 markus 1014: }
1.191 djm 1015: fclose(f);
1.317 markus 1016: free(line);
1.191 djm 1017:
1.269 djm 1018: if (invalid)
1.279 djm 1019: fatal("%s is not a public key file.", path);
1.12 markus 1020: exit(0);
1.8 markus 1021: }
1022:
1.119 djm 1023: static void
1.206 stevesk 1024: do_gen_all_hostkeys(struct passwd *pw)
1025: {
1026: struct {
1027: char *key_type;
1028: char *key_type_display;
1029: char *path;
1030: } key_types[] = {
1.267 djm 1031: #ifdef WITH_OPENSSL
1.206 stevesk 1032: { "rsa", "RSA" ,_PATH_HOST_RSA_KEY_FILE },
1033: { "ecdsa", "ECDSA",_PATH_HOST_ECDSA_KEY_FILE },
1.267 djm 1034: #endif /* WITH_OPENSSL */
1.238 markus 1035: { "ed25519", "ED25519",_PATH_HOST_ED25519_KEY_FILE },
1.313 markus 1036: #ifdef WITH_XMSS
1037: { "xmss", "XMSS",_PATH_HOST_XMSS_KEY_FILE },
1038: #endif /* WITH_XMSS */
1.206 stevesk 1039: { NULL, NULL, NULL }
1040: };
1041:
1.340 dtucker 1042: u_int32_t bits = 0;
1.206 stevesk 1043: int first = 0;
1044: struct stat st;
1.252 djm 1045: struct sshkey *private, *public;
1.307 djm 1046: char comment[1024], *prv_tmp, *pub_tmp, *prv_file, *pub_file;
1.252 djm 1047: int i, type, fd, r;
1.206 stevesk 1048:
1049: for (i = 0; key_types[i].key_type; i++) {
1.307 djm 1050: public = private = NULL;
1051: prv_tmp = pub_tmp = prv_file = pub_file = NULL;
1052:
1053: xasprintf(&prv_file, "%s%s",
1054: identity_file, key_types[i].path);
1055:
1056: /* Check whether private key exists and is not zero-length */
1057: if (stat(prv_file, &st) == 0) {
1058: if (st.st_size != 0)
1059: goto next;
1060: } else if (errno != ENOENT) {
1.269 djm 1061: error("Could not stat %s: %s", key_types[i].path,
1.206 stevesk 1062: strerror(errno));
1.307 djm 1063: goto failnext;
1.206 stevesk 1064: }
1065:
1.307 djm 1066: /*
1067: * Private key doesn't exist or is invalid; proceed with
1068: * key generation.
1069: */
1070: xasprintf(&prv_tmp, "%s%s.XXXXXXXXXX",
1071: identity_file, key_types[i].path);
1072: xasprintf(&pub_tmp, "%s%s.pub.XXXXXXXXXX",
1073: identity_file, key_types[i].path);
1074: xasprintf(&pub_file, "%s%s.pub",
1075: identity_file, key_types[i].path);
1076:
1.206 stevesk 1077: if (first == 0) {
1078: first = 1;
1079: printf("%s: generating new host keys: ", __progname);
1080: }
1081: printf("%s ", key_types[i].key_type_display);
1082: fflush(stdout);
1.252 djm 1083: type = sshkey_type_from_name(key_types[i].key_type);
1.307 djm 1084: if ((fd = mkstemp(prv_tmp)) == -1) {
1.409 djm 1085: error("Could not save your private key in %s: %s",
1.307 djm 1086: prv_tmp, strerror(errno));
1087: goto failnext;
1088: }
1.409 djm 1089: (void)close(fd); /* just using mkstemp() to reserve a name */
1.206 stevesk 1090: bits = 0;
1.255 djm 1091: type_bits_valid(type, NULL, &bits);
1.252 djm 1092: if ((r = sshkey_generate(type, bits, &private)) != 0) {
1.421 djm 1093: error_r(r, "sshkey_generate failed");
1.307 djm 1094: goto failnext;
1.206 stevesk 1095: }
1.252 djm 1096: if ((r = sshkey_from_private(private, &public)) != 0)
1.421 djm 1097: fatal_fr(r, "sshkey_from_private");
1.206 stevesk 1098: snprintf(comment, sizeof comment, "%s@%s", pw->pw_name,
1099: hostname);
1.307 djm 1100: if ((r = sshkey_save_private(private, prv_tmp, "",
1.336 djm 1101: comment, private_key_format, openssh_format_cipher,
1102: rounds)) != 0) {
1.421 djm 1103: error_r(r, "Saving key \"%s\" failed", prv_tmp);
1.307 djm 1104: goto failnext;
1.206 stevesk 1105: }
1.307 djm 1106: if ((fd = mkstemp(pub_tmp)) == -1) {
1107: error("Could not save your public key in %s: %s",
1108: pub_tmp, strerror(errno));
1109: goto failnext;
1.206 stevesk 1110: }
1.307 djm 1111: (void)fchmod(fd, 0644);
1.409 djm 1112: (void)close(fd);
1113: if ((r = sshkey_save_public(public, pub_tmp, comment)) != 0) {
1.421 djm 1114: error_r(r, "Unable to save public key to %s",
1115: identity_file);
1.307 djm 1116: goto failnext;
1117: }
1118:
1119: /* Rename temporary files to their permanent locations. */
1120: if (rename(pub_tmp, pub_file) != 0) {
1121: error("Unable to move %s into position: %s",
1122: pub_file, strerror(errno));
1123: goto failnext;
1124: }
1125: if (rename(prv_tmp, prv_file) != 0) {
1126: error("Unable to move %s into position: %s",
1127: key_types[i].path, strerror(errno));
1128: failnext:
1.206 stevesk 1129: first = 0;
1.307 djm 1130: goto next;
1.206 stevesk 1131: }
1.307 djm 1132: next:
1133: sshkey_free(private);
1.252 djm 1134: sshkey_free(public);
1.307 djm 1135: free(prv_tmp);
1136: free(pub_tmp);
1137: free(prv_file);
1138: free(pub_file);
1.206 stevesk 1139: }
1140: if (first != 0)
1141: printf("\n");
1142: }
1143:
1.256 djm 1144: struct known_hosts_ctx {
1.257 djm 1145: const char *host; /* Hostname searched for in find/delete case */
1146: FILE *out; /* Output file, stdout for find_hosts case */
1147: int has_unhashed; /* When hashing, original had unhashed hosts */
1148: int found_key; /* For find/delete, host was found */
1149: int invalid; /* File contained invalid items; don't delete */
1.325 djm 1150: int hash_hosts; /* Hash hostnames as we go */
1151: int find_host; /* Search for specific hostname */
1152: int delete_host; /* Delete host from known_hosts */
1.256 djm 1153: };
1154:
1155: static int
1156: known_hosts_hash(struct hostkey_foreach_line *l, void *_ctx)
1.119 djm 1157: {
1.256 djm 1158: struct known_hosts_ctx *ctx = (struct known_hosts_ctx *)_ctx;
1159: char *hashed, *cp, *hosts, *ohosts;
1160: int has_wild = l->hosts && strcspn(l->hosts, "*?!") != strlen(l->hosts);
1.298 dtucker 1161: int was_hashed = l->hosts && l->hosts[0] == HASH_DELIM;
1.256 djm 1162:
1.262 djm 1163: switch (l->status) {
1164: case HKF_STATUS_OK:
1165: case HKF_STATUS_MATCHED:
1166: /*
1.467 jsg 1167: * Don't hash hosts already hashed, with wildcard
1.262 djm 1168: * characters or a CA/revocation marker.
1169: */
1.296 djm 1170: if (was_hashed || has_wild || l->marker != MRK_NONE) {
1.262 djm 1171: fprintf(ctx->out, "%s\n", l->line);
1.325 djm 1172: if (has_wild && !ctx->find_host) {
1.297 dtucker 1173: logit("%s:%lu: ignoring host name "
1.269 djm 1174: "with wildcard: %.64s", l->path,
1.262 djm 1175: l->linenum, l->hosts);
1176: }
1177: return 0;
1178: }
1179: /*
1180: * Split any comma-separated hostnames from the host list,
1181: * hash and store separately.
1182: */
1183: ohosts = hosts = xstrdup(l->hosts);
1184: while ((cp = strsep(&hosts, ",")) != NULL && *cp != '\0') {
1.299 djm 1185: lowercase(cp);
1.262 djm 1186: if ((hashed = host_hash(cp, NULL, 0)) == NULL)
1187: fatal("hash_host failed");
1188: fprintf(ctx->out, "%s %s\n", hashed, l->rawkey);
1.438 dtucker 1189: free(hashed);
1.262 djm 1190: ctx->has_unhashed = 1;
1191: }
1192: free(ohosts);
1193: return 0;
1194: case HKF_STATUS_INVALID:
1195: /* Retain invalid lines, but mark file as invalid. */
1.256 djm 1196: ctx->invalid = 1;
1.297 dtucker 1197: logit("%s:%lu: invalid line", l->path, l->linenum);
1.262 djm 1198: /* FALLTHROUGH */
1199: default:
1.256 djm 1200: fprintf(ctx->out, "%s\n", l->line);
1201: return 0;
1202: }
1.262 djm 1203: /* NOTREACHED */
1204: return -1;
1.256 djm 1205: }
1206:
1207: static int
1208: known_hosts_find_delete(struct hostkey_foreach_line *l, void *_ctx)
1209: {
1210: struct known_hosts_ctx *ctx = (struct known_hosts_ctx *)_ctx;
1.272 djm 1211: enum sshkey_fp_rep rep;
1212: int fptype;
1.338 djm 1213: char *fp = NULL, *ra = NULL;
1.272 djm 1214:
1215: fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash;
1216: rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT;
1.256 djm 1217:
1.262 djm 1218: if (l->status == HKF_STATUS_MATCHED) {
1.325 djm 1219: if (ctx->delete_host) {
1.256 djm 1220: if (l->marker != MRK_NONE) {
1221: /* Don't remove CA and revocation lines */
1222: fprintf(ctx->out, "%s\n", l->line);
1223: } else {
1224: /*
1225: * Hostname matches and has no CA/revoke
1226: * marker, delete it by *not* writing the
1227: * line to ctx->out.
1228: */
1229: ctx->found_key = 1;
1230: if (!quiet)
1.297 dtucker 1231: printf("# Host %s found: line %lu\n",
1.256 djm 1232: ctx->host, l->linenum);
1233: }
1234: return 0;
1.325 djm 1235: } else if (ctx->find_host) {
1.256 djm 1236: ctx->found_key = 1;
1237: if (!quiet) {
1.297 dtucker 1238: printf("# Host %s found: line %lu %s\n",
1.256 djm 1239: ctx->host,
1240: l->linenum, l->marker == MRK_CA ? "CA" :
1241: (l->marker == MRK_REVOKE ? "REVOKED" : ""));
1242: }
1.325 djm 1243: if (ctx->hash_hosts)
1.256 djm 1244: known_hosts_hash(l, ctx);
1.272 djm 1245: else if (print_fingerprint) {
1246: fp = sshkey_fingerprint(l->key, fptype, rep);
1.338 djm 1247: ra = sshkey_fingerprint(l->key,
1248: fingerprint_hash, SSH_FP_RANDOMART);
1249: if (fp == NULL || ra == NULL)
1.421 djm 1250: fatal_f("sshkey_fingerprint failed");
1.385 claudio 1251: mprintf("%s %s %s%s%s\n", ctx->host,
1252: sshkey_type(l->key), fp,
1253: l->comment[0] ? " " : "",
1254: l->comment);
1.338 djm 1255: if (log_level_get() >= SYSLOG_LEVEL_VERBOSE)
1256: printf("%s\n", ra);
1257: free(ra);
1.272 djm 1258: free(fp);
1259: } else
1.256 djm 1260: fprintf(ctx->out, "%s\n", l->line);
1261: return 0;
1262: }
1.325 djm 1263: } else if (ctx->delete_host) {
1.256 djm 1264: /* Retain non-matching hosts when deleting */
1265: if (l->status == HKF_STATUS_INVALID) {
1266: ctx->invalid = 1;
1.297 dtucker 1267: logit("%s:%lu: invalid line", l->path, l->linenum);
1.256 djm 1268: }
1269: fprintf(ctx->out, "%s\n", l->line);
1.166 djm 1270: }
1.256 djm 1271: return 0;
1.119 djm 1272: }
1273:
1274: static void
1.325 djm 1275: do_known_hosts(struct passwd *pw, const char *name, int find_host,
1276: int delete_host, int hash_hosts)
1.119 djm 1277: {
1.258 deraadt 1278: char *cp, tmp[PATH_MAX], old[PATH_MAX];
1.257 djm 1279: int r, fd, oerrno, inplace = 0;
1.256 djm 1280: struct known_hosts_ctx ctx;
1.272 djm 1281: u_int foreach_options;
1.410 djm 1282: struct stat sb;
1.119 djm 1283:
1284: if (!have_identity) {
1285: cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
1286: if (strlcpy(identity_file, cp, sizeof(identity_file)) >=
1287: sizeof(identity_file))
1288: fatal("Specified known hosts path too long");
1.227 djm 1289: free(cp);
1.119 djm 1290: have_identity = 1;
1291: }
1.410 djm 1292: if (stat(identity_file, &sb) != 0)
1293: fatal("Cannot stat %s: %s", identity_file, strerror(errno));
1.119 djm 1294:
1.256 djm 1295: memset(&ctx, 0, sizeof(ctx));
1296: ctx.out = stdout;
1297: ctx.host = name;
1.325 djm 1298: ctx.hash_hosts = hash_hosts;
1299: ctx.find_host = find_host;
1300: ctx.delete_host = delete_host;
1.256 djm 1301:
1.119 djm 1302: /*
1303: * Find hosts goes to stdout, hash and deletions happen in-place
1304: * A corner case is ssh-keygen -HF foo, which should go to stdout
1305: */
1306: if (!find_host && (hash_hosts || delete_host)) {
1307: if (strlcpy(tmp, identity_file, sizeof(tmp)) >= sizeof(tmp) ||
1308: strlcat(tmp, ".XXXXXXXXXX", sizeof(tmp)) >= sizeof(tmp) ||
1309: strlcpy(old, identity_file, sizeof(old)) >= sizeof(old) ||
1310: strlcat(old, ".old", sizeof(old)) >= sizeof(old))
1311: fatal("known_hosts path too long");
1312: umask(077);
1.256 djm 1313: if ((fd = mkstemp(tmp)) == -1)
1.119 djm 1314: fatal("mkstemp: %s", strerror(errno));
1.256 djm 1315: if ((ctx.out = fdopen(fd, "w")) == NULL) {
1316: oerrno = errno;
1.119 djm 1317: unlink(tmp);
1.256 djm 1318: fatal("fdopen: %s", strerror(oerrno));
1.119 djm 1319: }
1.463 dtucker 1320: (void)fchmod(fd, sb.st_mode & 0644);
1.257 djm 1321: inplace = 1;
1.119 djm 1322: }
1.256 djm 1323: /* XXX support identity_file == "-" for stdin */
1.272 djm 1324: foreach_options = find_host ? HKF_WANT_MATCH : 0;
1325: foreach_options |= print_fingerprint ? HKF_WANT_PARSE_KEY : 0;
1.316 djm 1326: if ((r = hostkeys_foreach(identity_file, (find_host || !hash_hosts) ?
1.315 djm 1327: known_hosts_find_delete : known_hosts_hash, &ctx, name, NULL,
1.427 djm 1328: foreach_options, 0)) != 0) {
1.284 deraadt 1329: if (inplace)
1330: unlink(tmp);
1.421 djm 1331: fatal_fr(r, "hostkeys_foreach");
1.284 deraadt 1332: }
1.119 djm 1333:
1.257 djm 1334: if (inplace)
1.256 djm 1335: fclose(ctx.out);
1.119 djm 1336:
1.256 djm 1337: if (ctx.invalid) {
1.269 djm 1338: error("%s is not a valid known_hosts file.", identity_file);
1.257 djm 1339: if (inplace) {
1.269 djm 1340: error("Not replacing existing known_hosts "
1341: "file because of errors");
1.119 djm 1342: unlink(tmp);
1343: }
1344: exit(1);
1.256 djm 1345: } else if (delete_host && !ctx.found_key) {
1.269 djm 1346: logit("Host %s not found in %s", name, identity_file);
1.277 djm 1347: if (inplace)
1348: unlink(tmp);
1.257 djm 1349: } else if (inplace) {
1.119 djm 1350: /* Backup existing file */
1351: if (unlink(old) == -1 && errno != ENOENT)
1352: fatal("unlink %.100s: %s", old, strerror(errno));
1353: if (link(identity_file, old) == -1)
1354: fatal("link %.100s to %.100s: %s", identity_file, old,
1355: strerror(errno));
1356: /* Move new one into place */
1357: if (rename(tmp, identity_file) == -1) {
1358: error("rename\"%s\" to \"%s\": %s", tmp, identity_file,
1359: strerror(errno));
1360: unlink(tmp);
1361: unlink(old);
1362: exit(1);
1363: }
1364:
1.269 djm 1365: printf("%s updated.\n", identity_file);
1366: printf("Original contents retained as %s\n", old);
1.256 djm 1367: if (ctx.has_unhashed) {
1.269 djm 1368: logit("WARNING: %s contains unhashed entries", old);
1369: logit("Delete this file to ensure privacy "
1370: "of hostnames");
1.119 djm 1371: }
1372: }
1373:
1.256 djm 1374: exit (find_host && !ctx.found_key);
1.119 djm 1375: }
1376:
1.13 deraadt 1377: /*
1378: * Perform changing a passphrase. The argument is the passwd structure
1379: * for the current user.
1380: */
1.63 itojun 1381: static void
1.7 markus 1382: do_change_passphrase(struct passwd *pw)
1383: {
1.12 markus 1384: char *comment;
1385: char *old_passphrase, *passphrase1, *passphrase2;
1386: struct stat st;
1.252 djm 1387: struct sshkey *private;
1388: int r;
1.12 markus 1389:
1390: if (!have_identity)
1391: ask_filename(pw, "Enter file in which the key is");
1.333 deraadt 1392: if (stat(identity_file, &st) == -1)
1.269 djm 1393: fatal("%s: %s", identity_file, strerror(errno));
1.12 markus 1394: /* Try to load the file with empty passphrase. */
1.252 djm 1395: r = sshkey_load_private(identity_file, "", &private, &comment);
1396: if (r == SSH_ERR_KEY_WRONG_PASSPHRASE) {
1.12 markus 1397: if (identity_passphrase)
1398: old_passphrase = xstrdup(identity_passphrase);
1399: else
1.65 markus 1400: old_passphrase =
1401: read_passphrase("Enter old passphrase: ",
1402: RP_ALLOW_STDIN);
1.252 djm 1403: r = sshkey_load_private(identity_file, old_passphrase,
1404: &private, &comment);
1.399 jsg 1405: freezero(old_passphrase, strlen(old_passphrase));
1.252 djm 1406: if (r != 0)
1407: goto badkey;
1408: } else if (r != 0) {
1409: badkey:
1.421 djm 1410: fatal_r(r, "Failed to load key %s", identity_file);
1.12 markus 1411: }
1.266 djm 1412: if (comment)
1.294 djm 1413: mprintf("Key has comment '%s'\n", comment);
1.12 markus 1414:
1415: /* Ask the new passphrase (twice). */
1416: if (identity_new_passphrase) {
1417: passphrase1 = xstrdup(identity_new_passphrase);
1418: passphrase2 = NULL;
1419: } else {
1420: passphrase1 =
1.65 markus 1421: read_passphrase("Enter new passphrase (empty for no "
1422: "passphrase): ", RP_ALLOW_STDIN);
1423: passphrase2 = read_passphrase("Enter same passphrase again: ",
1.86 deraadt 1424: RP_ALLOW_STDIN);
1.12 markus 1425:
1426: /* Verify that they are the same. */
1427: if (strcmp(passphrase1, passphrase2) != 0) {
1.240 djm 1428: explicit_bzero(passphrase1, strlen(passphrase1));
1429: explicit_bzero(passphrase2, strlen(passphrase2));
1.227 djm 1430: free(passphrase1);
1431: free(passphrase2);
1.12 markus 1432: printf("Pass phrases do not match. Try again.\n");
1433: exit(1);
1434: }
1435: /* Destroy the other copy. */
1.399 jsg 1436: freezero(passphrase2, strlen(passphrase2));
1.12 markus 1437: }
1438:
1439: /* Save the file using the new passphrase. */
1.252 djm 1440: if ((r = sshkey_save_private(private, identity_file, passphrase1,
1.336 djm 1441: comment, private_key_format, openssh_format_cipher, rounds)) != 0) {
1.421 djm 1442: error_r(r, "Saving key \"%s\" failed", identity_file);
1.399 jsg 1443: freezero(passphrase1, strlen(passphrase1));
1.252 djm 1444: sshkey_free(private);
1.227 djm 1445: free(comment);
1.12 markus 1446: exit(1);
1447: }
1448: /* Destroy the passphrase and the copy of the key in memory. */
1.399 jsg 1449: freezero(passphrase1, strlen(passphrase1));
1.252 djm 1450: sshkey_free(private); /* Destroys contents */
1.227 djm 1451: free(comment);
1.1 deraadt 1452:
1.12 markus 1453: printf("Your identification has been saved with the new passphrase.\n");
1454: exit(0);
1.1 deraadt 1455: }
1456:
1.105 jakob 1457: /*
1458: * Print the SSHFP RR.
1459: */
1.138 jakob 1460: static int
1.325 djm 1461: do_print_resource_record(struct passwd *pw, char *fname, char *hname,
1.462 djm 1462: int print_generic, char * const *opts, size_t nopts)
1.105 jakob 1463: {
1.252 djm 1464: struct sshkey *public;
1.105 jakob 1465: char *comment = NULL;
1466: struct stat st;
1.462 djm 1467: int r, hash = -1;
1468: size_t i;
1.105 jakob 1469:
1.462 djm 1470: for (i = 0; i < nopts; i++) {
1471: if (strncasecmp(opts[i], "hashalg=", 8) == 0) {
1472: if ((hash = ssh_digest_alg_by_name(opts[i] + 8)) == -1)
1473: fatal("Unsupported hash algorithm");
1474: } else {
1475: error("Invalid option \"%s\"", opts[i]);
1476: return SSH_ERR_INVALID_ARGUMENT;
1477: }
1478: }
1.138 jakob 1479: if (fname == NULL)
1.421 djm 1480: fatal_f("no filename");
1.333 deraadt 1481: if (stat(fname, &st) == -1) {
1.138 jakob 1482: if (errno == ENOENT)
1483: return 0;
1.269 djm 1484: fatal("%s: %s", fname, strerror(errno));
1.105 jakob 1485: }
1.269 djm 1486: if ((r = sshkey_load_public(fname, &public, &comment)) != 0)
1.421 djm 1487: fatal_r(r, "Failed to read v2 public key from \"%s\"", fname);
1.462 djm 1488: export_dns_rr(hname, public, stdout, print_generic, hash);
1.252 djm 1489: sshkey_free(public);
1490: free(comment);
1491: return 1;
1.105 jakob 1492: }
1493:
1.13 deraadt 1494: /*
1495: * Change the comment of a private key file.
1496: */
1.63 itojun 1497: static void
1.325 djm 1498: do_change_comment(struct passwd *pw, const char *identity_comment)
1.1 deraadt 1499: {
1.46 deraadt 1500: char new_comment[1024], *comment, *passphrase;
1.252 djm 1501: struct sshkey *private;
1502: struct sshkey *public;
1.12 markus 1503: struct stat st;
1.409 djm 1504: int r;
1.12 markus 1505:
1506: if (!have_identity)
1507: ask_filename(pw, "Enter file in which the key is");
1.333 deraadt 1508: if (stat(identity_file, &st) == -1)
1.269 djm 1509: fatal("%s: %s", identity_file, strerror(errno));
1.252 djm 1510: if ((r = sshkey_load_private(identity_file, "",
1511: &private, &comment)) == 0)
1512: passphrase = xstrdup("");
1.269 djm 1513: else if (r != SSH_ERR_KEY_WRONG_PASSPHRASE)
1.421 djm 1514: fatal_r(r, "Cannot load private key \"%s\"", identity_file);
1.269 djm 1515: else {
1.12 markus 1516: if (identity_passphrase)
1517: passphrase = xstrdup(identity_passphrase);
1518: else if (identity_new_passphrase)
1519: passphrase = xstrdup(identity_new_passphrase);
1520: else
1.65 markus 1521: passphrase = read_passphrase("Enter passphrase: ",
1522: RP_ALLOW_STDIN);
1.12 markus 1523: /* Try to load using the passphrase. */
1.252 djm 1524: if ((r = sshkey_load_private(identity_file, passphrase,
1525: &private, &comment)) != 0) {
1.399 jsg 1526: freezero(passphrase, strlen(passphrase));
1.421 djm 1527: fatal_r(r, "Cannot load private key \"%s\"",
1528: identity_file);
1.12 markus 1529: }
1530: }
1.283 halex 1531:
1.313 markus 1532: if (private->type != KEY_ED25519 && private->type != KEY_XMSS &&
1.336 djm 1533: private_key_format != SSHKEY_PRIVATE_OPENSSH) {
1.302 djm 1534: error("Comments are only supported for keys stored in "
1.283 halex 1535: "the new format (-o).");
1.268 tobias 1536: explicit_bzero(passphrase, strlen(passphrase));
1.252 djm 1537: sshkey_free(private);
1.52 markus 1538: exit(1);
1.86 deraadt 1539: }
1.293 millert 1540: if (comment)
1.330 lum 1541: printf("Old comment: %s\n", comment);
1.293 millert 1542: else
1.330 lum 1543: printf("No existing comment\n");
1.12 markus 1544:
1545: if (identity_comment) {
1546: strlcpy(new_comment, identity_comment, sizeof(new_comment));
1547: } else {
1.330 lum 1548: printf("New comment: ");
1.12 markus 1549: fflush(stdout);
1550: if (!fgets(new_comment, sizeof(new_comment), stdin)) {
1.240 djm 1551: explicit_bzero(passphrase, strlen(passphrase));
1.252 djm 1552: sshkey_free(private);
1.12 markus 1553: exit(1);
1554: }
1.162 gilles 1555: new_comment[strcspn(new_comment, "\n")] = '\0';
1.12 markus 1556: }
1.330 lum 1557: if (comment != NULL && strcmp(comment, new_comment) == 0) {
1558: printf("No change to comment\n");
1559: free(passphrase);
1560: sshkey_free(private);
1561: free(comment);
1562: exit(0);
1563: }
1.12 markus 1564:
1565: /* Save the file using the new passphrase. */
1.252 djm 1566: if ((r = sshkey_save_private(private, identity_file, passphrase,
1.336 djm 1567: new_comment, private_key_format, openssh_format_cipher,
1568: rounds)) != 0) {
1.421 djm 1569: error_r(r, "Saving key \"%s\" failed", identity_file);
1.399 jsg 1570: freezero(passphrase, strlen(passphrase));
1.252 djm 1571: sshkey_free(private);
1.227 djm 1572: free(comment);
1.12 markus 1573: exit(1);
1574: }
1.399 jsg 1575: freezero(passphrase, strlen(passphrase));
1.252 djm 1576: if ((r = sshkey_from_private(private, &public)) != 0)
1.421 djm 1577: fatal_fr(r, "sshkey_from_private");
1.252 djm 1578: sshkey_free(private);
1.12 markus 1579:
1580: strlcat(identity_file, ".pub", sizeof(identity_file));
1.421 djm 1581: if ((r = sshkey_save_public(public, identity_file, new_comment)) != 0)
1582: fatal_r(r, "Unable to save public key to %s", identity_file);
1.252 djm 1583: sshkey_free(public);
1.227 djm 1584: free(comment);
1.1 deraadt 1585:
1.330 lum 1586: if (strlen(new_comment) > 0)
1587: printf("Comment '%s' applied\n", new_comment);
1588: else
1589: printf("Comment removed\n");
1590:
1.12 markus 1591: exit(0);
1.1 deraadt 1592: }
1593:
1.179 djm 1594: static void
1.415 djm 1595: cert_ext_add(const char *key, const char *value, int iscrit)
1.179 djm 1596: {
1.415 djm 1597: cert_ext = xreallocarray(cert_ext, ncert_ext + 1, sizeof(*cert_ext));
1598: cert_ext[ncert_ext].key = xstrdup(key);
1599: cert_ext[ncert_ext].val = value == NULL ? NULL : xstrdup(value);
1600: cert_ext[ncert_ext].crit = iscrit;
1601: ncert_ext++;
1.179 djm 1602: }
1603:
1.415 djm 1604: /* qsort(3) comparison function for certificate extensions */
1605: static int
1606: cert_ext_cmp(const void *_a, const void *_b)
1.179 djm 1607: {
1.415 djm 1608: const struct cert_ext *a = (const struct cert_ext *)_a;
1609: const struct cert_ext *b = (const struct cert_ext *)_b;
1.252 djm 1610: int r;
1.179 djm 1611:
1.415 djm 1612: if (a->crit != b->crit)
1613: return (a->crit < b->crit) ? -1 : 1;
1614: if ((r = strcmp(a->key, b->key)) != 0)
1615: return r;
1616: if ((a->val == NULL) != (b->val == NULL))
1617: return (a->val == NULL) ? -1 : 1;
1618: if (a->val != NULL && (r = strcmp(a->val, b->val)) != 0)
1619: return r;
1620: return 0;
1.179 djm 1621: }
1622:
1.190 djm 1623: #define OPTIONS_CRITICAL 1
1624: #define OPTIONS_EXTENSIONS 2
1.179 djm 1625: static void
1.252 djm 1626: prepare_options_buf(struct sshbuf *c, int which)
1.179 djm 1627: {
1.415 djm 1628: struct sshbuf *b;
1.300 djm 1629: size_t i;
1.415 djm 1630: int r;
1631: const struct cert_ext *ext;
1.300 djm 1632:
1.415 djm 1633: if ((b = sshbuf_new()) == NULL)
1.421 djm 1634: fatal_f("sshbuf_new failed");
1.252 djm 1635: sshbuf_reset(c);
1.415 djm 1636: for (i = 0; i < ncert_ext; i++) {
1637: ext = &cert_ext[i];
1638: if ((ext->crit && (which & OPTIONS_EXTENSIONS)) ||
1639: (!ext->crit && (which & OPTIONS_CRITICAL)))
1.300 djm 1640: continue;
1.415 djm 1641: if (ext->val == NULL) {
1642: /* flag option */
1.421 djm 1643: debug3_f("%s", ext->key);
1.415 djm 1644: if ((r = sshbuf_put_cstring(c, ext->key)) != 0 ||
1645: (r = sshbuf_put_string(c, NULL, 0)) != 0)
1.421 djm 1646: fatal_fr(r, "prepare flag");
1.415 djm 1647: } else {
1648: /* key/value option */
1.421 djm 1649: debug3_f("%s=%s", ext->key, ext->val);
1.415 djm 1650: sshbuf_reset(b);
1651: if ((r = sshbuf_put_cstring(c, ext->key)) != 0 ||
1652: (r = sshbuf_put_cstring(b, ext->val)) != 0 ||
1653: (r = sshbuf_put_stringb(c, b)) != 0)
1.421 djm 1654: fatal_fr(r, "prepare k/v");
1.300 djm 1655: }
1656: }
1.415 djm 1657: sshbuf_free(b);
1658: }
1659:
1660: static void
1661: finalise_cert_exts(void)
1662: {
1663: /* critical options */
1664: if (certflags_command != NULL)
1665: cert_ext_add("force-command", certflags_command, 1);
1666: if (certflags_src_addr != NULL)
1667: cert_ext_add("source-address", certflags_src_addr, 1);
1.453 naddy 1668: if ((certflags_flags & CERTOPT_REQUIRE_VERIFY) != 0)
1669: cert_ext_add("verify-required", NULL, 1);
1.415 djm 1670: /* extensions */
1671: if ((certflags_flags & CERTOPT_X_FWD) != 0)
1672: cert_ext_add("permit-X11-forwarding", NULL, 0);
1673: if ((certflags_flags & CERTOPT_AGENT_FWD) != 0)
1674: cert_ext_add("permit-agent-forwarding", NULL, 0);
1675: if ((certflags_flags & CERTOPT_PORT_FWD) != 0)
1676: cert_ext_add("permit-port-forwarding", NULL, 0);
1677: if ((certflags_flags & CERTOPT_PTY) != 0)
1678: cert_ext_add("permit-pty", NULL, 0);
1679: if ((certflags_flags & CERTOPT_USER_RC) != 0)
1680: cert_ext_add("permit-user-rc", NULL, 0);
1681: if ((certflags_flags & CERTOPT_NO_REQUIRE_USER_PRESENCE) != 0)
1682: cert_ext_add("no-touch-required", NULL, 0);
1683: /* order lexically by key */
1684: if (ncert_ext > 0)
1685: qsort(cert_ext, ncert_ext, sizeof(*cert_ext), cert_ext_cmp);
1.179 djm 1686: }
1687:
1.252 djm 1688: static struct sshkey *
1.197 djm 1689: load_pkcs11_key(char *path)
1690: {
1691: #ifdef ENABLE_PKCS11
1.252 djm 1692: struct sshkey **keys = NULL, *public, *private = NULL;
1693: int r, i, nkeys;
1.197 djm 1694:
1.252 djm 1695: if ((r = sshkey_load_public(path, &public, NULL)) != 0)
1.421 djm 1696: fatal_r(r, "Couldn't load CA public key \"%s\"", path);
1.197 djm 1697:
1.392 djm 1698: nkeys = pkcs11_add_provider(pkcs11provider, identity_passphrase,
1699: &keys, NULL);
1.421 djm 1700: debug3_f("%d keys", nkeys);
1.197 djm 1701: if (nkeys <= 0)
1702: fatal("cannot read public key from pkcs11");
1703: for (i = 0; i < nkeys; i++) {
1.252 djm 1704: if (sshkey_equal_public(public, keys[i])) {
1.197 djm 1705: private = keys[i];
1706: continue;
1707: }
1.252 djm 1708: sshkey_free(keys[i]);
1.197 djm 1709: }
1.227 djm 1710: free(keys);
1.252 djm 1711: sshkey_free(public);
1.197 djm 1712: return private;
1713: #else
1714: fatal("no pkcs11 support");
1715: #endif /* ENABLE_PKCS11 */
1716: }
1717:
1.305 djm 1718: /* Signer for sshkey_certify_custom that uses the agent */
1719: static int
1.332 djm 1720: agent_signer(struct sshkey *key, u_char **sigp, size_t *lenp,
1.305 djm 1721: const u_char *data, size_t datalen,
1.416 djm 1722: const char *alg, const char *provider, const char *pin,
1723: u_int compat, void *ctx)
1.305 djm 1724: {
1725: int *agent_fdp = (int *)ctx;
1726:
1727: return ssh_agent_sign(*agent_fdp, key, sigp, lenp,
1728: data, datalen, alg, compat);
1729: }
1730:
1.179 djm 1731: static void
1.325 djm 1732: do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
1.326 djm 1733: unsigned long long cert_serial, int cert_serial_autoinc,
1734: int argc, char **argv)
1.179 djm 1735: {
1.409 djm 1736: int r, i, found, agent_fd = -1;
1.179 djm 1737: u_int n;
1.252 djm 1738: struct sshkey *ca, *public;
1.374 djm 1739: char valid[64], *otmp, *tmp, *cp, *out, *comment;
1.416 djm 1740: char *ca_fp = NULL, **plist = NULL, *pin = NULL;
1.305 djm 1741: struct ssh_identitylist *agent_ids;
1742: size_t j;
1.374 djm 1743: struct notifier_ctx *notifier = NULL;
1.186 djm 1744:
1.246 markus 1745: #ifdef ENABLE_PKCS11
1.197 djm 1746: pkcs11_init(1);
1.246 markus 1747: #endif
1.197 djm 1748: tmp = tilde_expand_filename(ca_key_path, pw->pw_uid);
1749: if (pkcs11provider != NULL) {
1.305 djm 1750: /* If a PKCS#11 token was specified then try to use it */
1.197 djm 1751: if ((ca = load_pkcs11_key(tmp)) == NULL)
1752: fatal("No PKCS#11 key matching %s found", ca_key_path);
1.305 djm 1753: } else if (prefer_agent) {
1754: /*
1755: * Agent signature requested. Try to use agent after making
1756: * sure the public key specified is actually present in the
1757: * agent.
1758: */
1759: if ((r = sshkey_load_public(tmp, &ca, NULL)) != 0)
1.421 djm 1760: fatal_r(r, "Cannot load CA public key %s", tmp);
1.305 djm 1761: if ((r = ssh_get_authentication_socket(&agent_fd)) != 0)
1.421 djm 1762: fatal_r(r, "Cannot use public key for CA signature");
1.305 djm 1763: if ((r = ssh_fetch_identitylist(agent_fd, &agent_ids)) != 0)
1.421 djm 1764: fatal_r(r, "Retrieve agent key list");
1.305 djm 1765: found = 0;
1766: for (j = 0; j < agent_ids->nkeys; j++) {
1767: if (sshkey_equal(ca, agent_ids->keys[j])) {
1768: found = 1;
1769: break;
1770: }
1771: }
1772: if (!found)
1773: fatal("CA key %s not found in agent", tmp);
1774: ssh_free_identitylist(agent_ids);
1775: ca->flags |= SSHKEY_FLAG_EXT;
1776: } else {
1777: /* CA key is assumed to be a private key on the filesystem */
1.341 djm 1778: ca = load_identity(tmp, NULL);
1.416 djm 1779: if (sshkey_is_sk(ca) &&
1780: (ca->sk_flags & SSH_SK_USER_VERIFICATION_REQD)) {
1781: if ((pin = read_passphrase("Enter PIN for CA key: ",
1782: RP_ALLOW_STDIN)) == NULL)
1.421 djm 1783: fatal_f("couldn't read PIN");
1.416 djm 1784: }
1.305 djm 1785: }
1.227 djm 1786: free(tmp);
1.197 djm 1787:
1.390 djm 1788: if (key_type_name != NULL) {
1789: if (sshkey_type_from_name(key_type_name) != ca->type) {
1790: fatal("CA key type %s doesn't match specified %s",
1791: sshkey_ssh_name(ca), key_type_name);
1792: }
1793: } else if (ca->type == KEY_RSA) {
1794: /* Default to a good signature algorithm */
1795: key_type_name = "rsa-sha2-512";
1.290 djm 1796: }
1.374 djm 1797: ca_fp = sshkey_fingerprint(ca, fingerprint_hash, SSH_FP_DEFAULT);
1.290 djm 1798:
1.415 djm 1799: finalise_cert_exts();
1.179 djm 1800: for (i = 0; i < argc; i++) {
1801: /* Split list of principals */
1802: n = 0;
1803: if (cert_principals != NULL) {
1804: otmp = tmp = xstrdup(cert_principals);
1805: plist = NULL;
1806: for (; (cp = strsep(&tmp, ",")) != NULL; n++) {
1.270 deraadt 1807: plist = xreallocarray(plist, n + 1, sizeof(*plist));
1.179 djm 1808: if (*(plist[n] = xstrdup(cp)) == '\0')
1809: fatal("Empty principal name");
1810: }
1.227 djm 1811: free(otmp);
1.179 djm 1812: }
1.312 djm 1813: if (n > SSHKEY_CERT_MAX_PRINCIPALS)
1814: fatal("Too many certificate principals specified");
1.337 djm 1815:
1.179 djm 1816: tmp = tilde_expand_filename(argv[i], pw->pw_uid);
1.252 djm 1817: if ((r = sshkey_load_public(tmp, &public, &comment)) != 0)
1.421 djm 1818: fatal_r(r, "load pubkey \"%s\"", tmp);
1.366 djm 1819: if (sshkey_is_cert(public))
1.421 djm 1820: fatal_f("key \"%s\" type %s cannot be certified",
1821: tmp, sshkey_type(public));
1.179 djm 1822:
1823: /* Prepare certificate to sign */
1.275 djm 1824: if ((r = sshkey_to_certified(public)) != 0)
1.421 djm 1825: fatal_r(r, "Could not upgrade key %s to certificate", tmp);
1.179 djm 1826: public->cert->type = cert_key_type;
1.186 djm 1827: public->cert->serial = (u_int64_t)cert_serial;
1.179 djm 1828: public->cert->key_id = xstrdup(cert_key_id);
1829: public->cert->nprincipals = n;
1830: public->cert->principals = plist;
1831: public->cert->valid_after = cert_valid_from;
1832: public->cert->valid_before = cert_valid_to;
1.275 djm 1833: prepare_options_buf(public->cert->critical, OPTIONS_CRITICAL);
1834: prepare_options_buf(public->cert->extensions,
1835: OPTIONS_EXTENSIONS);
1.252 djm 1836: if ((r = sshkey_from_private(ca,
1837: &public->cert->signature_key)) != 0)
1.421 djm 1838: fatal_r(r, "sshkey_from_private (ca key)");
1.179 djm 1839:
1.305 djm 1840: if (agent_fd != -1 && (ca->flags & SSHKEY_FLAG_EXT) != 0) {
1841: if ((r = sshkey_certify_custom(public, ca,
1.416 djm 1842: key_type_name, sk_provider, NULL, agent_signer,
1.358 djm 1843: &agent_fd)) != 0)
1.421 djm 1844: fatal_r(r, "Couldn't certify %s via agent", tmp);
1.305 djm 1845: } else {
1.374 djm 1846: if (sshkey_is_sk(ca) &&
1847: (ca->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
1848: notifier = notify_start(0,
1849: "Confirm user presence for key %s %s",
1850: sshkey_type(ca), ca_fp);
1851: }
1852: r = sshkey_certify(public, ca, key_type_name,
1.416 djm 1853: sk_provider, pin);
1.424 djm 1854: notify_complete(notifier, "User presence confirmed");
1.374 djm 1855: if (r != 0)
1.421 djm 1856: fatal_r(r, "Couldn't certify key %s", tmp);
1.305 djm 1857: }
1.179 djm 1858:
1859: if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0)
1860: *cp = '\0';
1861: xasprintf(&out, "%s-cert.pub", tmp);
1.227 djm 1862: free(tmp);
1.179 djm 1863:
1.409 djm 1864: if ((r = sshkey_save_public(public, out, comment)) != 0) {
1.421 djm 1865: fatal_r(r, "Unable to save public key to %s",
1866: identity_file);
1.409 djm 1867: }
1.179 djm 1868:
1.186 djm 1869: if (!quiet) {
1.282 djm 1870: sshkey_format_cert_validity(public->cert,
1.281 djm 1871: valid, sizeof(valid));
1.186 djm 1872: logit("Signed %s key %s: id \"%s\" serial %llu%s%s "
1.282 djm 1873: "valid %s", sshkey_cert_type(public),
1.205 djm 1874: out, public->cert->key_id,
1875: (unsigned long long)public->cert->serial,
1.179 djm 1876: cert_principals != NULL ? " for " : "",
1877: cert_principals != NULL ? cert_principals : "",
1.281 djm 1878: valid);
1.186 djm 1879: }
1.179 djm 1880:
1.252 djm 1881: sshkey_free(public);
1.227 djm 1882: free(out);
1.326 djm 1883: if (cert_serial_autoinc)
1884: cert_serial++;
1.179 djm 1885: }
1.416 djm 1886: if (pin != NULL)
1887: freezero(pin, strlen(pin));
1.374 djm 1888: free(ca_fp);
1.246 markus 1889: #ifdef ENABLE_PKCS11
1.197 djm 1890: pkcs11_terminate();
1.246 markus 1891: #endif
1.179 djm 1892: exit(0);
1893: }
1894:
1895: static u_int64_t
1896: parse_relative_time(const char *s, time_t now)
1897: {
1898: int64_t mul, secs;
1899:
1900: mul = *s == '-' ? -1 : 1;
1901:
1902: if ((secs = convtime(s + 1)) == -1)
1903: fatal("Invalid relative certificate time %s", s);
1904: if (mul == -1 && secs > now)
1905: fatal("Certificate time %s cannot be represented", s);
1906: return now + (u_int64_t)(secs * mul);
1907: }
1908:
1909: static void
1.459 djm 1910: parse_hex_u64(const char *s, uint64_t *up)
1911: {
1912: char *ep;
1913: unsigned long long ull;
1914:
1915: errno = 0;
1916: ull = strtoull(s, &ep, 16);
1917: if (*s == '\0' || *ep != '\0')
1918: fatal("Invalid certificate time: not a number");
1919: if (errno == ERANGE && ull == ULONG_MAX)
1920: fatal_fr(SSH_ERR_SYSTEM_ERROR, "Invalid certificate time");
1921: *up = (uint64_t)ull;
1922: }
1923:
1924: static void
1.179 djm 1925: parse_cert_times(char *timespec)
1926: {
1927: char *from, *to;
1928: time_t now = time(NULL);
1929: int64_t secs;
1930:
1931: /* +timespec relative to now */
1932: if (*timespec == '+' && strchr(timespec, ':') == NULL) {
1933: if ((secs = convtime(timespec + 1)) == -1)
1934: fatal("Invalid relative certificate life %s", timespec);
1935: cert_valid_to = now + secs;
1936: /*
1937: * Backdate certificate one minute to avoid problems on hosts
1938: * with poorly-synchronised clocks.
1939: */
1940: cert_valid_from = ((now - 59)/ 60) * 60;
1941: return;
1942: }
1943:
1944: /*
1945: * from:to, where
1.459 djm 1946: * from := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS | 0x... | "always"
1947: * to := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS | 0x... | "forever"
1.179 djm 1948: */
1949: from = xstrdup(timespec);
1950: to = strchr(from, ':');
1951: if (to == NULL || from == to || *(to + 1) == '\0')
1.181 djm 1952: fatal("Invalid certificate life specification %s", timespec);
1.179 djm 1953: *to++ = '\0';
1954:
1955: if (*from == '-' || *from == '+')
1956: cert_valid_from = parse_relative_time(from, now);
1.308 djm 1957: else if (strcmp(from, "always") == 0)
1958: cert_valid_from = 0;
1.459 djm 1959: else if (strncmp(from, "0x", 2) == 0)
1960: parse_hex_u64(from, &cert_valid_from);
1.314 djm 1961: else if (parse_absolute_time(from, &cert_valid_from) != 0)
1962: fatal("Invalid from time \"%s\"", from);
1.179 djm 1963:
1964: if (*to == '-' || *to == '+')
1.235 djm 1965: cert_valid_to = parse_relative_time(to, now);
1.308 djm 1966: else if (strcmp(to, "forever") == 0)
1967: cert_valid_to = ~(u_int64_t)0;
1.460 djm 1968: else if (strncmp(to, "0x", 2) == 0)
1.459 djm 1969: parse_hex_u64(to, &cert_valid_to);
1.314 djm 1970: else if (parse_absolute_time(to, &cert_valid_to) != 0)
1971: fatal("Invalid to time \"%s\"", to);
1.179 djm 1972:
1973: if (cert_valid_to <= cert_valid_from)
1974: fatal("Empty certificate validity interval");
1.227 djm 1975: free(from);
1.179 djm 1976: }
1977:
1978: static void
1.186 djm 1979: add_cert_option(char *opt)
1.179 djm 1980: {
1.300 djm 1981: char *val, *cp;
1982: int iscrit = 0;
1.179 djm 1983:
1.208 stevesk 1984: if (strcasecmp(opt, "clear") == 0)
1.190 djm 1985: certflags_flags = 0;
1.179 djm 1986: else if (strcasecmp(opt, "no-x11-forwarding") == 0)
1.190 djm 1987: certflags_flags &= ~CERTOPT_X_FWD;
1.179 djm 1988: else if (strcasecmp(opt, "permit-x11-forwarding") == 0)
1.190 djm 1989: certflags_flags |= CERTOPT_X_FWD;
1.179 djm 1990: else if (strcasecmp(opt, "no-agent-forwarding") == 0)
1.190 djm 1991: certflags_flags &= ~CERTOPT_AGENT_FWD;
1.179 djm 1992: else if (strcasecmp(opt, "permit-agent-forwarding") == 0)
1.190 djm 1993: certflags_flags |= CERTOPT_AGENT_FWD;
1.179 djm 1994: else if (strcasecmp(opt, "no-port-forwarding") == 0)
1.190 djm 1995: certflags_flags &= ~CERTOPT_PORT_FWD;
1.179 djm 1996: else if (strcasecmp(opt, "permit-port-forwarding") == 0)
1.190 djm 1997: certflags_flags |= CERTOPT_PORT_FWD;
1.179 djm 1998: else if (strcasecmp(opt, "no-pty") == 0)
1.190 djm 1999: certflags_flags &= ~CERTOPT_PTY;
1.179 djm 2000: else if (strcasecmp(opt, "permit-pty") == 0)
1.190 djm 2001: certflags_flags |= CERTOPT_PTY;
1.179 djm 2002: else if (strcasecmp(opt, "no-user-rc") == 0)
1.190 djm 2003: certflags_flags &= ~CERTOPT_USER_RC;
1.179 djm 2004: else if (strcasecmp(opt, "permit-user-rc") == 0)
1.190 djm 2005: certflags_flags |= CERTOPT_USER_RC;
1.371 djm 2006: else if (strcasecmp(opt, "touch-required") == 0)
2007: certflags_flags &= ~CERTOPT_NO_REQUIRE_USER_PRESENCE;
2008: else if (strcasecmp(opt, "no-touch-required") == 0)
2009: certflags_flags |= CERTOPT_NO_REQUIRE_USER_PRESENCE;
1.453 naddy 2010: else if (strcasecmp(opt, "no-verify-required") == 0)
2011: certflags_flags &= ~CERTOPT_REQUIRE_VERIFY;
2012: else if (strcasecmp(opt, "verify-required") == 0)
2013: certflags_flags |= CERTOPT_REQUIRE_VERIFY;
1.179 djm 2014: else if (strncasecmp(opt, "force-command=", 14) == 0) {
2015: val = opt + 14;
2016: if (*val == '\0')
1.186 djm 2017: fatal("Empty force-command option");
1.190 djm 2018: if (certflags_command != NULL)
1.179 djm 2019: fatal("force-command already specified");
1.190 djm 2020: certflags_command = xstrdup(val);
1.179 djm 2021: } else if (strncasecmp(opt, "source-address=", 15) == 0) {
2022: val = opt + 15;
2023: if (*val == '\0')
1.186 djm 2024: fatal("Empty source-address option");
1.190 djm 2025: if (certflags_src_addr != NULL)
1.179 djm 2026: fatal("source-address already specified");
2027: if (addr_match_cidr_list(NULL, val) != 0)
2028: fatal("Invalid source-address list");
1.190 djm 2029: certflags_src_addr = xstrdup(val);
1.300 djm 2030: } else if (strncasecmp(opt, "extension:", 10) == 0 ||
1.429 djm 2031: (iscrit = (strncasecmp(opt, "critical:", 9) == 0))) {
1.300 djm 2032: val = xstrdup(strchr(opt, ':') + 1);
2033: if ((cp = strchr(val, '=')) != NULL)
2034: *cp++ = '\0';
1.415 djm 2035: cert_ext_add(val, cp, iscrit);
2036: free(val);
1.179 djm 2037: } else
1.186 djm 2038: fatal("Unsupported certificate option \"%s\"", opt);
1.179 djm 2039: }
2040:
1.63 itojun 2041: static void
1.275 djm 2042: show_options(struct sshbuf *optbuf, int in_critical)
1.192 djm 2043: {
1.415 djm 2044: char *name, *arg, *hex;
1.252 djm 2045: struct sshbuf *options, *option = NULL;
2046: int r;
2047:
2048: if ((options = sshbuf_fromb(optbuf)) == NULL)
1.421 djm 2049: fatal_f("sshbuf_fromb failed");
1.252 djm 2050: while (sshbuf_len(options) != 0) {
2051: sshbuf_free(option);
2052: option = NULL;
2053: if ((r = sshbuf_get_cstring(options, &name, NULL)) != 0 ||
2054: (r = sshbuf_froms(options, &option)) != 0)
1.421 djm 2055: fatal_fr(r, "parse option");
1.192 djm 2056: printf(" %s", name);
1.275 djm 2057: if (!in_critical &&
1.192 djm 2058: (strcmp(name, "permit-X11-forwarding") == 0 ||
2059: strcmp(name, "permit-agent-forwarding") == 0 ||
2060: strcmp(name, "permit-port-forwarding") == 0 ||
2061: strcmp(name, "permit-pty") == 0 ||
1.371 djm 2062: strcmp(name, "permit-user-rc") == 0 ||
2063: strcmp(name, "no-touch-required") == 0)) {
1.192 djm 2064: printf("\n");
1.371 djm 2065: } else if (in_critical &&
1.192 djm 2066: (strcmp(name, "force-command") == 0 ||
2067: strcmp(name, "source-address") == 0)) {
1.252 djm 2068: if ((r = sshbuf_get_cstring(option, &arg, NULL)) != 0)
1.421 djm 2069: fatal_fr(r, "parse critical");
1.245 djm 2070: printf(" %s\n", arg);
2071: free(arg);
1.453 naddy 2072: } else if (in_critical &&
2073: strcmp(name, "verify-required") == 0) {
2074: printf("\n");
1.415 djm 2075: } else if (sshbuf_len(option) > 0) {
2076: hex = sshbuf_dtob16(option);
2077: printf(" UNKNOWN OPTION: %s (len %zu)\n",
2078: hex, sshbuf_len(option));
1.252 djm 2079: sshbuf_reset(option);
1.415 djm 2080: free(hex);
2081: } else
2082: printf(" UNKNOWN FLAG OPTION\n");
1.227 djm 2083: free(name);
1.252 djm 2084: if (sshbuf_len(option) != 0)
1.192 djm 2085: fatal("Option corrupt: extra data at end");
2086: }
1.252 djm 2087: sshbuf_free(option);
2088: sshbuf_free(options);
1.192 djm 2089: }
2090:
2091: static void
1.278 djm 2092: print_cert(struct sshkey *key)
1.182 djm 2093: {
1.281 djm 2094: char valid[64], *key_fp, *ca_fp;
1.275 djm 2095: u_int i;
1.186 djm 2096:
1.252 djm 2097: key_fp = sshkey_fingerprint(key, fingerprint_hash, SSH_FP_DEFAULT);
2098: ca_fp = sshkey_fingerprint(key->cert->signature_key,
1.251 djm 2099: fingerprint_hash, SSH_FP_DEFAULT);
1.259 djm 2100: if (key_fp == NULL || ca_fp == NULL)
1.421 djm 2101: fatal_f("sshkey_fingerprint fail");
1.281 djm 2102: sshkey_format_cert_validity(key->cert, valid, sizeof(valid));
1.182 djm 2103:
1.252 djm 2104: printf(" Type: %s %s certificate\n", sshkey_ssh_name(key),
2105: sshkey_cert_type(key));
2106: printf(" Public key: %s %s\n", sshkey_type(key), key_fp);
1.323 djm 2107: printf(" Signing CA: %s %s (using %s)\n",
2108: sshkey_type(key->cert->signature_key), ca_fp,
2109: key->cert->signature_type);
1.186 djm 2110: printf(" Key ID: \"%s\"\n", key->cert->key_id);
1.275 djm 2111: printf(" Serial: %llu\n", (unsigned long long)key->cert->serial);
1.281 djm 2112: printf(" Valid: %s\n", valid);
1.182 djm 2113: printf(" Principals: ");
2114: if (key->cert->nprincipals == 0)
2115: printf("(none)\n");
2116: else {
2117: for (i = 0; i < key->cert->nprincipals; i++)
2118: printf("\n %s",
2119: key->cert->principals[i]);
2120: printf("\n");
2121: }
1.186 djm 2122: printf(" Critical Options: ");
1.252 djm 2123: if (sshbuf_len(key->cert->critical) == 0)
1.182 djm 2124: printf("(none)\n");
2125: else {
2126: printf("\n");
1.275 djm 2127: show_options(key->cert->critical, 1);
1.186 djm 2128: }
1.275 djm 2129: printf(" Extensions: ");
2130: if (sshbuf_len(key->cert->extensions) == 0)
2131: printf("(none)\n");
2132: else {
2133: printf("\n");
2134: show_options(key->cert->extensions, 0);
1.182 djm 2135: }
1.278 djm 2136: }
2137:
2138: static void
2139: do_show_cert(struct passwd *pw)
2140: {
2141: struct sshkey *key = NULL;
2142: struct stat st;
2143: int r, is_stdin = 0, ok = 0;
2144: FILE *f;
1.317 markus 2145: char *cp, *line = NULL;
1.278 djm 2146: const char *path;
1.317 markus 2147: size_t linesize = 0;
1.289 djm 2148: u_long lnum = 0;
1.278 djm 2149:
2150: if (!have_identity)
2151: ask_filename(pw, "Enter file in which the key is");
1.333 deraadt 2152: if (strcmp(identity_file, "-") != 0 && stat(identity_file, &st) == -1)
1.278 djm 2153: fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
2154:
2155: path = identity_file;
2156: if (strcmp(path, "-") == 0) {
2157: f = stdin;
2158: path = "(stdin)";
2159: is_stdin = 1;
2160: } else if ((f = fopen(identity_file, "r")) == NULL)
2161: fatal("fopen %s: %s", identity_file, strerror(errno));
2162:
1.317 markus 2163: while (getline(&line, &linesize, f) != -1) {
2164: lnum++;
1.278 djm 2165: sshkey_free(key);
2166: key = NULL;
2167: /* Trim leading space and comments */
2168: cp = line + strspn(line, " \t");
2169: if (*cp == '#' || *cp == '\0')
2170: continue;
2171: if ((key = sshkey_new(KEY_UNSPEC)) == NULL)
1.304 markus 2172: fatal("sshkey_new");
1.278 djm 2173: if ((r = sshkey_read(key, &cp)) != 0) {
1.421 djm 2174: error_r(r, "%s:%lu: invalid key", path, lnum);
1.278 djm 2175: continue;
2176: }
2177: if (!sshkey_is_cert(key)) {
2178: error("%s:%lu is not a certificate", path, lnum);
2179: continue;
2180: }
2181: ok = 1;
2182: if (!is_stdin && lnum == 1)
2183: printf("%s:\n", path);
2184: else
2185: printf("%s:%lu:\n", path, lnum);
2186: print_cert(key);
2187: }
1.317 markus 2188: free(line);
1.278 djm 2189: sshkey_free(key);
2190: fclose(f);
2191: exit(ok ? 0 : 1);
1.182 djm 2192: }
2193:
2194: static void
1.223 djm 2195: load_krl(const char *path, struct ssh_krl **krlp)
2196: {
1.252 djm 2197: struct sshbuf *krlbuf;
1.393 djm 2198: int r;
1.223 djm 2199:
1.393 djm 2200: if ((r = sshbuf_load_file(path, &krlbuf)) != 0)
1.421 djm 2201: fatal_r(r, "Unable to load KRL %s", path);
1.223 djm 2202: /* XXX check sigs */
1.252 djm 2203: if ((r = ssh_krl_from_blob(krlbuf, krlp, NULL, 0)) != 0 ||
1.223 djm 2204: *krlp == NULL)
1.421 djm 2205: fatal_r(r, "Invalid KRL file %s", path);
1.252 djm 2206: sshbuf_free(krlbuf);
1.223 djm 2207: }
2208:
2209: static void
1.320 djm 2210: hash_to_blob(const char *cp, u_char **blobp, size_t *lenp,
2211: const char *file, u_long lnum)
2212: {
2213: char *tmp;
2214: size_t tlen;
2215: struct sshbuf *b;
2216: int r;
2217:
2218: if (strncmp(cp, "SHA256:", 7) != 0)
2219: fatal("%s:%lu: unsupported hash algorithm", file, lnum);
2220: cp += 7;
2221:
2222: /*
2223: * OpenSSH base64 hashes omit trailing '='
2224: * characters; put them back for decode.
2225: */
2226: tlen = strlen(cp);
2227: tmp = xmalloc(tlen + 4 + 1);
2228: strlcpy(tmp, cp, tlen + 1);
2229: while ((tlen % 4) != 0) {
2230: tmp[tlen++] = '=';
2231: tmp[tlen] = '\0';
2232: }
2233: if ((b = sshbuf_new()) == NULL)
1.421 djm 2234: fatal_f("sshbuf_new failed");
1.320 djm 2235: if ((r = sshbuf_b64tod(b, tmp)) != 0)
1.421 djm 2236: fatal_r(r, "%s:%lu: decode hash failed", file, lnum);
1.320 djm 2237: free(tmp);
2238: *lenp = sshbuf_len(b);
2239: *blobp = xmalloc(*lenp);
2240: memcpy(*blobp, sshbuf_ptr(b), *lenp);
2241: sshbuf_free(b);
2242: }
2243:
2244: static void
1.261 djm 2245: update_krl_from_file(struct passwd *pw, const char *file, int wild_ca,
1.252 djm 2246: const struct sshkey *ca, struct ssh_krl *krl)
1.223 djm 2247: {
1.252 djm 2248: struct sshkey *key = NULL;
1.223 djm 2249: u_long lnum = 0;
1.317 markus 2250: char *path, *cp, *ep, *line = NULL;
1.320 djm 2251: u_char *blob = NULL;
2252: size_t blen = 0, linesize = 0;
1.223 djm 2253: unsigned long long serial, serial2;
1.320 djm 2254: int i, was_explicit_key, was_sha1, was_sha256, was_hash, r;
1.223 djm 2255: FILE *krl_spec;
2256:
2257: path = tilde_expand_filename(file, pw->pw_uid);
2258: if (strcmp(path, "-") == 0) {
2259: krl_spec = stdin;
2260: free(path);
2261: path = xstrdup("(standard input)");
2262: } else if ((krl_spec = fopen(path, "r")) == NULL)
2263: fatal("fopen %s: %s", path, strerror(errno));
2264:
2265: if (!quiet)
2266: printf("Revoking from %s\n", path);
1.317 markus 2267: while (getline(&line, &linesize, krl_spec) != -1) {
2268: lnum++;
1.320 djm 2269: was_explicit_key = was_sha1 = was_sha256 = was_hash = 0;
1.223 djm 2270: cp = line + strspn(line, " \t");
2271: /* Trim trailing space, comments and strip \n */
2272: for (i = 0, r = -1; cp[i] != '\0'; i++) {
2273: if (cp[i] == '#' || cp[i] == '\n') {
2274: cp[i] = '\0';
2275: break;
2276: }
2277: if (cp[i] == ' ' || cp[i] == '\t') {
2278: /* Remember the start of a span of whitespace */
2279: if (r == -1)
2280: r = i;
2281: } else
2282: r = -1;
2283: }
2284: if (r != -1)
2285: cp[r] = '\0';
2286: if (*cp == '\0')
2287: continue;
2288: if (strncasecmp(cp, "serial:", 7) == 0) {
1.261 djm 2289: if (ca == NULL && !wild_ca) {
1.231 djm 2290: fatal("revoking certificates by serial number "
1.223 djm 2291: "requires specification of a CA key");
2292: }
2293: cp += 7;
2294: cp = cp + strspn(cp, " \t");
2295: errno = 0;
2296: serial = strtoull(cp, &ep, 0);
2297: if (*cp == '\0' || (*ep != '\0' && *ep != '-'))
2298: fatal("%s:%lu: invalid serial \"%s\"",
2299: path, lnum, cp);
2300: if (errno == ERANGE && serial == ULLONG_MAX)
2301: fatal("%s:%lu: serial out of range",
2302: path, lnum);
2303: serial2 = serial;
2304: if (*ep == '-') {
2305: cp = ep + 1;
2306: errno = 0;
2307: serial2 = strtoull(cp, &ep, 0);
2308: if (*cp == '\0' || *ep != '\0')
2309: fatal("%s:%lu: invalid serial \"%s\"",
2310: path, lnum, cp);
2311: if (errno == ERANGE && serial2 == ULLONG_MAX)
2312: fatal("%s:%lu: serial out of range",
2313: path, lnum);
2314: if (serial2 <= serial)
2315: fatal("%s:%lu: invalid serial range "
2316: "%llu:%llu", path, lnum,
2317: (unsigned long long)serial,
2318: (unsigned long long)serial2);
2319: }
2320: if (ssh_krl_revoke_cert_by_serial_range(krl,
2321: ca, serial, serial2) != 0) {
1.421 djm 2322: fatal_f("revoke serial failed");
1.223 djm 2323: }
2324: } else if (strncasecmp(cp, "id:", 3) == 0) {
1.261 djm 2325: if (ca == NULL && !wild_ca) {
1.232 djm 2326: fatal("revoking certificates by key ID "
1.223 djm 2327: "requires specification of a CA key");
2328: }
2329: cp += 3;
2330: cp = cp + strspn(cp, " \t");
2331: if (ssh_krl_revoke_cert_by_key_id(krl, ca, cp) != 0)
1.421 djm 2332: fatal_f("revoke key ID failed");
1.320 djm 2333: } else if (strncasecmp(cp, "hash:", 5) == 0) {
2334: cp += 5;
2335: cp = cp + strspn(cp, " \t");
2336: hash_to_blob(cp, &blob, &blen, file, lnum);
2337: r = ssh_krl_revoke_key_sha256(krl, blob, blen);
1.401 markus 2338: if (r != 0)
1.421 djm 2339: fatal_fr(r, "revoke key failed");
1.223 djm 2340: } else {
2341: if (strncasecmp(cp, "key:", 4) == 0) {
2342: cp += 4;
2343: cp = cp + strspn(cp, " \t");
2344: was_explicit_key = 1;
2345: } else if (strncasecmp(cp, "sha1:", 5) == 0) {
2346: cp += 5;
2347: cp = cp + strspn(cp, " \t");
2348: was_sha1 = 1;
1.320 djm 2349: } else if (strncasecmp(cp, "sha256:", 7) == 0) {
2350: cp += 7;
2351: cp = cp + strspn(cp, " \t");
2352: was_sha256 = 1;
1.223 djm 2353: /*
2354: * Just try to process the line as a key.
2355: * Parsing will fail if it isn't.
2356: */
2357: }
1.252 djm 2358: if ((key = sshkey_new(KEY_UNSPEC)) == NULL)
1.304 markus 2359: fatal("sshkey_new");
1.252 djm 2360: if ((r = sshkey_read(key, &cp)) != 0)
1.421 djm 2361: fatal_r(r, "%s:%lu: invalid key", path, lnum);
1.223 djm 2362: if (was_explicit_key)
2363: r = ssh_krl_revoke_key_explicit(krl, key);
1.320 djm 2364: else if (was_sha1) {
2365: if (sshkey_fingerprint_raw(key,
2366: SSH_DIGEST_SHA1, &blob, &blen) != 0) {
2367: fatal("%s:%lu: fingerprint failed",
2368: file, lnum);
2369: }
2370: r = ssh_krl_revoke_key_sha1(krl, blob, blen);
2371: } else if (was_sha256) {
2372: if (sshkey_fingerprint_raw(key,
2373: SSH_DIGEST_SHA256, &blob, &blen) != 0) {
2374: fatal("%s:%lu: fingerprint failed",
2375: file, lnum);
2376: }
2377: r = ssh_krl_revoke_key_sha256(krl, blob, blen);
2378: } else
1.223 djm 2379: r = ssh_krl_revoke_key(krl, key);
2380: if (r != 0)
1.421 djm 2381: fatal_fr(r, "revoke key failed");
1.320 djm 2382: freezero(blob, blen);
2383: blob = NULL;
2384: blen = 0;
1.252 djm 2385: sshkey_free(key);
1.223 djm 2386: }
2387: }
2388: if (strcmp(path, "-") != 0)
2389: fclose(krl_spec);
1.317 markus 2390: free(line);
1.226 djm 2391: free(path);
1.223 djm 2392: }
2393:
2394: static void
1.325 djm 2395: do_gen_krl(struct passwd *pw, int updating, const char *ca_key_path,
2396: unsigned long long krl_version, const char *krl_comment,
2397: int argc, char **argv)
1.223 djm 2398: {
2399: struct ssh_krl *krl;
2400: struct stat sb;
1.252 djm 2401: struct sshkey *ca = NULL;
1.393 djm 2402: int i, r, wild_ca = 0;
1.223 djm 2403: char *tmp;
1.252 djm 2404: struct sshbuf *kbuf;
1.223 djm 2405:
2406: if (*identity_file == '\0')
2407: fatal("KRL generation requires an output file");
2408: if (stat(identity_file, &sb) == -1) {
2409: if (errno != ENOENT)
2410: fatal("Cannot access KRL \"%s\": %s",
2411: identity_file, strerror(errno));
2412: if (updating)
2413: fatal("KRL \"%s\" does not exist", identity_file);
2414: }
2415: if (ca_key_path != NULL) {
1.261 djm 2416: if (strcasecmp(ca_key_path, "none") == 0)
2417: wild_ca = 1;
2418: else {
2419: tmp = tilde_expand_filename(ca_key_path, pw->pw_uid);
2420: if ((r = sshkey_load_public(tmp, &ca, NULL)) != 0)
1.421 djm 2421: fatal_r(r, "Cannot load CA public key %s", tmp);
1.261 djm 2422: free(tmp);
2423: }
1.223 djm 2424: }
2425:
2426: if (updating)
2427: load_krl(identity_file, &krl);
2428: else if ((krl = ssh_krl_init()) == NULL)
2429: fatal("couldn't create KRL");
2430:
1.325 djm 2431: if (krl_version != 0)
2432: ssh_krl_set_version(krl, krl_version);
2433: if (krl_comment != NULL)
2434: ssh_krl_set_comment(krl, krl_comment);
1.223 djm 2435:
2436: for (i = 0; i < argc; i++)
1.261 djm 2437: update_krl_from_file(pw, argv[i], wild_ca, ca, krl);
1.223 djm 2438:
1.252 djm 2439: if ((kbuf = sshbuf_new()) == NULL)
2440: fatal("sshbuf_new failed");
2441: if (ssh_krl_to_blob(krl, kbuf, NULL, 0) != 0)
1.223 djm 2442: fatal("Couldn't generate KRL");
1.393 djm 2443: if ((r = sshbuf_write_file(identity_file, kbuf)) != 0)
1.223 djm 2444: fatal("write %s: %s", identity_file, strerror(errno));
1.252 djm 2445: sshbuf_free(kbuf);
1.223 djm 2446: ssh_krl_free(krl);
1.286 mmcc 2447: sshkey_free(ca);
1.223 djm 2448: }
2449:
2450: static void
1.405 djm 2451: do_check_krl(struct passwd *pw, int print_krl, int argc, char **argv)
1.223 djm 2452: {
2453: int i, r, ret = 0;
2454: char *comment;
2455: struct ssh_krl *krl;
1.252 djm 2456: struct sshkey *k;
1.223 djm 2457:
2458: if (*identity_file == '\0')
2459: fatal("KRL checking requires an input file");
2460: load_krl(identity_file, &krl);
1.405 djm 2461: if (print_krl)
2462: krl_dump(krl, stdout);
1.223 djm 2463: for (i = 0; i < argc; i++) {
1.252 djm 2464: if ((r = sshkey_load_public(argv[i], &k, &comment)) != 0)
1.421 djm 2465: fatal_r(r, "Cannot load public key %s", argv[i]);
1.223 djm 2466: r = ssh_krl_check_key(krl, k);
2467: printf("%s%s%s%s: %s\n", argv[i],
2468: *comment ? " (" : "", comment, *comment ? ")" : "",
2469: r == 0 ? "ok" : "REVOKED");
2470: if (r != 0)
2471: ret = 1;
1.252 djm 2472: sshkey_free(k);
1.223 djm 2473: free(comment);
2474: }
2475: ssh_krl_free(krl);
2476: exit(ret);
2477: }
2478:
1.344 djm 2479: static struct sshkey *
2480: load_sign_key(const char *keypath, const struct sshkey *pubkey)
2481: {
2482: size_t i, slen, plen = strlen(keypath);
2483: char *privpath = xstrdup(keypath);
1.448 djm 2484: static const char * const suffixes[] = { "-cert.pub", ".pub", NULL };
1.344 djm 2485: struct sshkey *ret = NULL, *privkey = NULL;
1.451 djm 2486: int r, waspub = 0;
2487: struct stat st;
1.344 djm 2488:
2489: /*
1.404 djm 2490: * If passed a public key filename, then try to locate the corresponding
1.344 djm 2491: * private key. This lets us specify certificates on the command-line
2492: * and have ssh-keygen find the appropriate private key.
2493: */
2494: for (i = 0; suffixes[i]; i++) {
2495: slen = strlen(suffixes[i]);
2496: if (plen <= slen ||
2497: strcmp(privpath + plen - slen, suffixes[i]) != 0)
2498: continue;
2499: privpath[plen - slen] = '\0';
1.421 djm 2500: debug_f("%s looks like a public key, using private key "
2501: "path %s instead", keypath, privpath);
1.451 djm 2502: waspub = 1;
1.344 djm 2503: }
1.451 djm 2504: if (waspub && stat(privpath, &st) != 0 && errno == ENOENT)
2505: fatal("No private key found for public key \"%s\"", keypath);
2506: if ((r = sshkey_load_private(privpath, "", &privkey, NULL)) != 0 &&
2507: (r != SSH_ERR_KEY_WRONG_PASSPHRASE)) {
2508: debug_fr(r, "load private key \"%s\"", privpath);
2509: fatal("No private key found for \"%s\"", privpath);
2510: } else if (privkey == NULL)
2511: privkey = load_identity(privpath, NULL);
2512:
1.344 djm 2513: if (!sshkey_equal_public(pubkey, privkey)) {
2514: error("Public key %s doesn't match private %s",
2515: keypath, privpath);
2516: goto done;
2517: }
2518: if (sshkey_is_cert(pubkey) && !sshkey_is_cert(privkey)) {
2519: /*
2520: * Graft the certificate onto the private key to make
2521: * it capable of signing.
2522: */
2523: if ((r = sshkey_to_certified(privkey)) != 0) {
1.421 djm 2524: error_fr(r, "sshkey_to_certified");
1.344 djm 2525: goto done;
2526: }
2527: if ((r = sshkey_cert_copy(pubkey, privkey)) != 0) {
1.421 djm 2528: error_fr(r, "sshkey_cert_copy");
1.344 djm 2529: goto done;
2530: }
2531: }
2532: /* success */
2533: ret = privkey;
2534: privkey = NULL;
2535: done:
2536: sshkey_free(privkey);
2537: free(privpath);
2538: return ret;
2539: }
2540:
2541: static int
2542: sign_one(struct sshkey *signkey, const char *filename, int fd,
1.445 djm 2543: const char *sig_namespace, const char *hashalg, sshsig_signer *signer,
2544: void *signer_ctx)
1.344 djm 2545: {
2546: struct sshbuf *sigbuf = NULL, *abuf = NULL;
2547: int r = SSH_ERR_INTERNAL_ERROR, wfd = -1, oerrno;
1.363 djm 2548: char *wfile = NULL, *asig = NULL, *fp = NULL;
1.416 djm 2549: char *pin = NULL, *prompt = NULL;
1.344 djm 2550:
2551: if (!quiet) {
2552: if (fd == STDIN_FILENO)
2553: fprintf(stderr, "Signing data on standard input\n");
2554: else
2555: fprintf(stderr, "Signing file %s\n", filename);
1.363 djm 2556: }
1.416 djm 2557: if (signer == NULL && sshkey_is_sk(signkey)) {
2558: if ((signkey->sk_flags & SSH_SK_USER_VERIFICATION_REQD)) {
2559: xasprintf(&prompt, "Enter PIN for %s key: ",
2560: sshkey_type(signkey));
2561: if ((pin = read_passphrase(prompt,
2562: RP_ALLOW_STDIN)) == NULL)
1.421 djm 2563: fatal_f("couldn't read PIN");
1.416 djm 2564: }
2565: if ((signkey->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
2566: if ((fp = sshkey_fingerprint(signkey, fingerprint_hash,
2567: SSH_FP_DEFAULT)) == NULL)
1.421 djm 2568: fatal_f("fingerprint failed");
1.416 djm 2569: fprintf(stderr, "Confirm user presence for key %s %s\n",
2570: sshkey_type(signkey), fp);
2571: free(fp);
2572: }
1.344 djm 2573: }
1.445 djm 2574: if ((r = sshsig_sign_fd(signkey, hashalg, sk_provider, pin,
1.416 djm 2575: fd, sig_namespace, &sigbuf, signer, signer_ctx)) != 0) {
1.421 djm 2576: error_r(r, "Signing %s failed", filename);
1.344 djm 2577: goto out;
2578: }
2579: if ((r = sshsig_armor(sigbuf, &abuf)) != 0) {
1.421 djm 2580: error_fr(r, "sshsig_armor");
1.344 djm 2581: goto out;
2582: }
2583: if ((asig = sshbuf_dup_string(abuf)) == NULL) {
1.421 djm 2584: error_f("buffer error");
1.344 djm 2585: r = SSH_ERR_ALLOC_FAIL;
2586: goto out;
2587: }
2588:
2589: if (fd == STDIN_FILENO) {
2590: fputs(asig, stdout);
2591: fflush(stdout);
2592: } else {
2593: xasprintf(&wfile, "%s.sig", filename);
2594: if (confirm_overwrite(wfile)) {
2595: if ((wfd = open(wfile, O_WRONLY|O_CREAT|O_TRUNC,
2596: 0666)) == -1) {
2597: oerrno = errno;
2598: error("Cannot open %s: %s",
2599: wfile, strerror(errno));
2600: errno = oerrno;
2601: r = SSH_ERR_SYSTEM_ERROR;
2602: goto out;
2603: }
2604: if (atomicio(vwrite, wfd, asig,
2605: strlen(asig)) != strlen(asig)) {
2606: oerrno = errno;
2607: error("Cannot write to %s: %s",
2608: wfile, strerror(errno));
2609: errno = oerrno;
2610: r = SSH_ERR_SYSTEM_ERROR;
2611: goto out;
2612: }
2613: if (!quiet) {
2614: fprintf(stderr, "Write signature to %s\n",
2615: wfile);
2616: }
2617: }
2618: }
2619: /* success */
2620: r = 0;
2621: out:
2622: free(wfile);
1.416 djm 2623: free(prompt);
1.344 djm 2624: free(asig);
1.416 djm 2625: if (pin != NULL)
2626: freezero(pin, strlen(pin));
1.344 djm 2627: sshbuf_free(abuf);
2628: sshbuf_free(sigbuf);
2629: if (wfd != -1)
2630: close(wfd);
2631: return r;
2632: }
2633:
2634: static int
1.445 djm 2635: sig_process_opts(char * const *opts, size_t nopts, char **hashalgp,
2636: uint64_t *verify_timep, int *print_pubkey)
1.443 djm 2637: {
2638: size_t i;
2639: time_t now;
2640:
2641: if (verify_timep != NULL)
2642: *verify_timep = 0;
2643: if (print_pubkey != NULL)
2644: *print_pubkey = 0;
1.445 djm 2645: if (hashalgp != NULL)
2646: *hashalgp = NULL;
1.443 djm 2647: for (i = 0; i < nopts; i++) {
1.445 djm 2648: if (hashalgp != NULL &&
2649: strncasecmp(opts[i], "hashalg=", 8) == 0) {
2650: *hashalgp = xstrdup(opts[i] + 8);
2651: } else if (verify_timep &&
1.443 djm 2652: strncasecmp(opts[i], "verify-time=", 12) == 0) {
2653: if (parse_absolute_time(opts[i] + 12,
2654: verify_timep) != 0 || *verify_timep == 0) {
2655: error("Invalid \"verify-time\" option");
2656: return SSH_ERR_INVALID_ARGUMENT;
2657: }
2658: } else if (print_pubkey &&
2659: strcasecmp(opts[i], "print-pubkey") == 0) {
2660: *print_pubkey = 1;
2661: } else {
2662: error("Invalid option \"%s\"", opts[i]);
2663: return SSH_ERR_INVALID_ARGUMENT;
2664: }
2665: }
2666: if (verify_timep && *verify_timep == 0) {
2667: if ((now = time(NULL)) < 0) {
2668: error("Time is before epoch");
2669: return SSH_ERR_INVALID_ARGUMENT;
2670: }
2671: *verify_timep = (uint64_t)now;
2672: }
2673: return 0;
2674: }
2675:
2676:
2677: static int
1.452 djm 2678: sig_sign(const char *keypath, const char *sig_namespace, int require_agent,
2679: int argc, char **argv, char * const *opts, size_t nopts)
1.344 djm 2680: {
2681: int i, fd = -1, r, ret = -1;
2682: int agent_fd = -1;
2683: struct sshkey *pubkey = NULL, *privkey = NULL, *signkey = NULL;
2684: sshsig_signer *signer = NULL;
1.445 djm 2685: char *hashalg = NULL;
1.344 djm 2686:
2687: /* Check file arguments. */
2688: for (i = 0; i < argc; i++) {
2689: if (strcmp(argv[i], "-") != 0)
2690: continue;
2691: if (i > 0 || argc > 1)
2692: fatal("Cannot sign mix of paths and standard input");
2693: }
2694:
1.445 djm 2695: if (sig_process_opts(opts, nopts, &hashalg, NULL, NULL) != 0)
2696: goto done; /* error already logged */
2697:
1.344 djm 2698: if ((r = sshkey_load_public(keypath, &pubkey, NULL)) != 0) {
1.421 djm 2699: error_r(r, "Couldn't load public key %s", keypath);
1.344 djm 2700: goto done;
2701: }
2702:
1.452 djm 2703: if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) {
2704: if (require_agent)
2705: fatal("Couldn't get agent socket");
1.421 djm 2706: debug_r(r, "Couldn't get agent socket");
1.452 djm 2707: } else {
1.344 djm 2708: if ((r = ssh_agent_has_key(agent_fd, pubkey)) == 0)
2709: signer = agent_signer;
1.452 djm 2710: else {
2711: if (require_agent)
2712: fatal("Couldn't find key in agent");
1.421 djm 2713: debug_r(r, "Couldn't find key in agent");
1.452 djm 2714: }
1.344 djm 2715: }
2716:
2717: if (signer == NULL) {
2718: /* Not using agent - try to load private key */
2719: if ((privkey = load_sign_key(keypath, pubkey)) == NULL)
2720: goto done;
2721: signkey = privkey;
2722: } else {
2723: /* Will use key in agent */
2724: signkey = pubkey;
2725: }
2726:
2727: if (argc == 0) {
2728: if ((r = sign_one(signkey, "(stdin)", STDIN_FILENO,
1.445 djm 2729: sig_namespace, hashalg, signer, &agent_fd)) != 0)
1.344 djm 2730: goto done;
2731: } else {
2732: for (i = 0; i < argc; i++) {
2733: if (strcmp(argv[i], "-") == 0)
2734: fd = STDIN_FILENO;
2735: else if ((fd = open(argv[i], O_RDONLY)) == -1) {
2736: error("Cannot open %s for signing: %s",
2737: argv[i], strerror(errno));
2738: goto done;
2739: }
2740: if ((r = sign_one(signkey, argv[i], fd, sig_namespace,
1.445 djm 2741: hashalg, signer, &agent_fd)) != 0)
1.344 djm 2742: goto done;
2743: if (fd != STDIN_FILENO)
2744: close(fd);
2745: fd = -1;
2746: }
2747: }
2748:
2749: ret = 0;
2750: done:
2751: if (fd != -1 && fd != STDIN_FILENO)
2752: close(fd);
2753: sshkey_free(pubkey);
2754: sshkey_free(privkey);
1.445 djm 2755: free(hashalg);
1.344 djm 2756: return ret;
1.432 djm 2757: }
2758:
2759: static int
1.386 djm 2760: sig_verify(const char *signature, const char *sig_namespace,
1.432 djm 2761: const char *principal, const char *allowed_keys, const char *revoked_keys,
2762: char * const *opts, size_t nopts)
1.344 djm 2763: {
1.393 djm 2764: int r, ret = -1;
1.435 djm 2765: int print_pubkey = 0;
1.344 djm 2766: struct sshbuf *sigbuf = NULL, *abuf = NULL;
2767: struct sshkey *sign_key = NULL;
2768: char *fp = NULL;
1.370 djm 2769: struct sshkey_sig_details *sig_details = NULL;
1.432 djm 2770: uint64_t verify_time = 0;
2771:
1.445 djm 2772: if (sig_process_opts(opts, nopts, NULL, &verify_time,
2773: &print_pubkey) != 0)
1.432 djm 2774: goto done; /* error already logged */
1.344 djm 2775:
1.370 djm 2776: memset(&sig_details, 0, sizeof(sig_details));
1.393 djm 2777: if ((r = sshbuf_load_file(signature, &abuf)) != 0) {
1.421 djm 2778: error_r(r, "Couldn't read signature file");
1.344 djm 2779: goto done;
2780: }
2781:
2782: if ((r = sshsig_dearmor(abuf, &sigbuf)) != 0) {
1.421 djm 2783: error_fr(r, "sshsig_armor");
1.386 djm 2784: goto done;
1.344 djm 2785: }
2786: if ((r = sshsig_verify_fd(sigbuf, STDIN_FILENO, sig_namespace,
1.370 djm 2787: &sign_key, &sig_details)) != 0)
1.344 djm 2788: goto done; /* sshsig_verify() prints error */
2789:
2790: if ((fp = sshkey_fingerprint(sign_key, fingerprint_hash,
2791: SSH_FP_DEFAULT)) == NULL)
1.421 djm 2792: fatal_f("sshkey_fingerprint failed");
1.344 djm 2793: debug("Valid (unverified) signature from key %s", fp);
1.370 djm 2794: if (sig_details != NULL) {
1.421 djm 2795: debug2_f("signature details: counter = %u, flags = 0x%02x",
2796: sig_details->sk_counter, sig_details->sk_flags);
1.370 djm 2797: }
1.344 djm 2798: free(fp);
2799: fp = NULL;
2800:
2801: if (revoked_keys != NULL) {
1.345 djm 2802: if ((r = sshkey_check_revoked(sign_key, revoked_keys)) != 0) {
1.421 djm 2803: debug3_fr(r, "sshkey_check_revoked");
1.345 djm 2804: goto done;
2805: }
1.344 djm 2806: }
2807:
1.421 djm 2808: if (allowed_keys != NULL && (r = sshsig_check_allowed_keys(allowed_keys,
1.432 djm 2809: sign_key, principal, sig_namespace, verify_time)) != 0) {
1.421 djm 2810: debug3_fr(r, "sshsig_check_allowed_keys");
1.344 djm 2811: goto done;
2812: }
2813: /* success */
2814: ret = 0;
2815: done:
2816: if (!quiet) {
2817: if (ret == 0) {
2818: if ((fp = sshkey_fingerprint(sign_key, fingerprint_hash,
1.421 djm 2819: SSH_FP_DEFAULT)) == NULL)
2820: fatal_f("sshkey_fingerprint failed");
1.350 djm 2821: if (principal == NULL) {
2822: printf("Good \"%s\" signature with %s key %s\n",
1.429 djm 2823: sig_namespace, sshkey_type(sign_key), fp);
1.350 djm 2824:
2825: } else {
2826: printf("Good \"%s\" signature for %s with %s key %s\n",
1.429 djm 2827: sig_namespace, principal,
2828: sshkey_type(sign_key), fp);
1.350 djm 2829: }
1.344 djm 2830: } else {
2831: printf("Could not verify signature.\n");
2832: }
2833: }
1.435 djm 2834: /* Print the signature key if requested */
2835: if (ret == 0 && print_pubkey && sign_key != NULL) {
2836: if ((r = sshkey_write(sign_key, stdout)) == 0)
2837: fputc('\n', stdout);
2838: else {
2839: error_r(r, "Could not print public key.\n");
2840: ret = -1;
2841: }
2842: }
1.344 djm 2843: sshbuf_free(sigbuf);
2844: sshbuf_free(abuf);
2845: sshkey_free(sign_key);
1.370 djm 2846: sshkey_sig_details_free(sig_details);
1.344 djm 2847: free(fp);
2848: return ret;
2849: }
2850:
1.386 djm 2851: static int
1.432 djm 2852: sig_find_principals(const char *signature, const char *allowed_keys,
2853: char * const *opts, size_t nopts)
2854: {
1.393 djm 2855: int r, ret = -1;
1.386 djm 2856: struct sshbuf *sigbuf = NULL, *abuf = NULL;
2857: struct sshkey *sign_key = NULL;
1.391 djm 2858: char *principals = NULL, *cp, *tmp;
1.432 djm 2859: uint64_t verify_time = 0;
2860:
1.445 djm 2861: if (sig_process_opts(opts, nopts, NULL, &verify_time, NULL) != 0)
1.432 djm 2862: goto done; /* error already logged */
1.386 djm 2863:
1.393 djm 2864: if ((r = sshbuf_load_file(signature, &abuf)) != 0) {
1.421 djm 2865: error_r(r, "Couldn't read signature file");
1.386 djm 2866: goto done;
2867: }
2868: if ((r = sshsig_dearmor(abuf, &sigbuf)) != 0) {
1.421 djm 2869: error_fr(r, "sshsig_armor");
1.386 djm 2870: goto done;
2871: }
2872: if ((r = sshsig_get_pubkey(sigbuf, &sign_key)) != 0) {
1.421 djm 2873: error_fr(r, "sshsig_get_pubkey");
1.386 djm 2874: goto done;
2875: }
1.388 djm 2876: if ((r = sshsig_find_principals(allowed_keys, sign_key,
1.432 djm 2877: verify_time, &principals)) != 0) {
1.431 djm 2878: if (r != SSH_ERR_KEY_NOT_FOUND)
2879: error_fr(r, "sshsig_find_principal");
1.386 djm 2880: goto done;
2881: }
2882: ret = 0;
2883: done:
2884: if (ret == 0 ) {
1.391 djm 2885: /* Emit matching principals one per line */
2886: tmp = principals;
2887: while ((cp = strsep(&tmp, ",")) != NULL && *cp != '\0')
2888: puts(cp);
1.386 djm 2889: } else {
1.391 djm 2890: fprintf(stderr, "No principal matched.\n");
1.386 djm 2891: }
2892: sshbuf_free(sigbuf);
2893: sshbuf_free(abuf);
2894: sshkey_free(sign_key);
1.388 djm 2895: free(principals);
1.386 djm 2896: return ret;
2897: }
2898:
1.441 djm 2899: static int
2900: sig_match_principals(const char *allowed_keys, char *principal,
2901: char * const *opts, size_t nopts)
2902: {
2903: int r;
2904: char **principals = NULL;
2905: size_t i, nprincipals = 0;
2906:
1.445 djm 2907: if ((r = sig_process_opts(opts, nopts, NULL, NULL, NULL)) != 0)
1.441 djm 2908: return r; /* error already logged */
2909:
2910: if ((r = sshsig_match_principals(allowed_keys, principal,
2911: &principals, &nprincipals)) != 0) {
2912: debug_f("match: %s", ssh_err(r));
2913: fprintf(stderr, "No principal matched.\n");
2914: return r;
2915: }
2916: for (i = 0; i < nprincipals; i++) {
2917: printf("%s\n", principals[i]);
2918: free(principals[i]);
2919: }
2920: free(principals);
2921:
2922: return 0;
2923: }
2924:
1.223 djm 2925: static void
1.376 djm 2926: do_moduli_gen(const char *out_file, char **opts, size_t nopts)
2927: {
2928: #ifdef WITH_OPENSSL
2929: /* Moduli generation/screening */
2930: u_int32_t memory = 0;
2931: BIGNUM *start = NULL;
2932: int moduli_bits = 0;
2933: FILE *out;
2934: size_t i;
2935: const char *errstr;
2936:
2937: /* Parse options */
2938: for (i = 0; i < nopts; i++) {
2939: if (strncmp(opts[i], "memory=", 7) == 0) {
2940: memory = (u_int32_t)strtonum(opts[i]+7, 1,
2941: UINT_MAX, &errstr);
2942: if (errstr) {
2943: fatal("Memory limit is %s: %s",
2944: errstr, opts[i]+7);
2945: }
2946: } else if (strncmp(opts[i], "start=", 6) == 0) {
2947: /* XXX - also compare length against bits */
2948: if (BN_hex2bn(&start, opts[i]+6) == 0)
2949: fatal("Invalid start point.");
2950: } else if (strncmp(opts[i], "bits=", 5) == 0) {
2951: moduli_bits = (int)strtonum(opts[i]+5, 1,
2952: INT_MAX, &errstr);
2953: if (errstr) {
2954: fatal("Invalid number: %s (%s)",
2955: opts[i]+12, errstr);
2956: }
2957: } else {
2958: fatal("Option \"%s\" is unsupported for moduli "
2959: "generation", opts[i]);
2960: }
2961: }
2962:
2963: if ((out = fopen(out_file, "w")) == NULL) {
2964: fatal("Couldn't open modulus candidate file \"%s\": %s",
2965: out_file, strerror(errno));
2966: }
2967: setvbuf(out, NULL, _IOLBF, 0);
2968:
2969: if (moduli_bits == 0)
2970: moduli_bits = DEFAULT_BITS;
2971: if (gen_candidates(out, memory, moduli_bits, start) != 0)
2972: fatal("modulus candidate generation failed");
2973: #else /* WITH_OPENSSL */
2974: fatal("Moduli generation is not supported");
2975: #endif /* WITH_OPENSSL */
2976: }
2977:
2978: static void
2979: do_moduli_screen(const char *out_file, char **opts, size_t nopts)
2980: {
2981: #ifdef WITH_OPENSSL
2982: /* Moduli generation/screening */
2983: char *checkpoint = NULL;
2984: u_int32_t generator_wanted = 0;
2985: unsigned long start_lineno = 0, lines_to_process = 0;
2986: int prime_tests = 0;
2987: FILE *out, *in = stdin;
2988: size_t i;
2989: const char *errstr;
2990:
2991: /* Parse options */
2992: for (i = 0; i < nopts; i++) {
2993: if (strncmp(opts[i], "lines=", 6) == 0) {
2994: lines_to_process = strtoul(opts[i]+6, NULL, 10);
2995: } else if (strncmp(opts[i], "start-line=", 11) == 0) {
2996: start_lineno = strtoul(opts[i]+11, NULL, 10);
2997: } else if (strncmp(opts[i], "checkpoint=", 11) == 0) {
1.465 dtucker 2998: free(checkpoint);
1.376 djm 2999: checkpoint = xstrdup(opts[i]+11);
3000: } else if (strncmp(opts[i], "generator=", 10) == 0) {
3001: generator_wanted = (u_int32_t)strtonum(
3002: opts[i]+10, 1, UINT_MAX, &errstr);
3003: if (errstr != NULL) {
3004: fatal("Generator invalid: %s (%s)",
3005: opts[i]+10, errstr);
3006: }
3007: } else if (strncmp(opts[i], "prime-tests=", 12) == 0) {
3008: prime_tests = (int)strtonum(opts[i]+12, 1,
3009: INT_MAX, &errstr);
3010: if (errstr) {
3011: fatal("Invalid number: %s (%s)",
3012: opts[i]+12, errstr);
3013: }
3014: } else {
3015: fatal("Option \"%s\" is unsupported for moduli "
3016: "screening", opts[i]);
3017: }
3018: }
3019:
3020: if (have_identity && strcmp(identity_file, "-") != 0) {
3021: if ((in = fopen(identity_file, "r")) == NULL) {
3022: fatal("Couldn't open modulus candidate "
3023: "file \"%s\": %s", identity_file,
3024: strerror(errno));
3025: }
3026: }
3027:
3028: if ((out = fopen(out_file, "a")) == NULL) {
3029: fatal("Couldn't open moduli file \"%s\": %s",
3030: out_file, strerror(errno));
3031: }
3032: setvbuf(out, NULL, _IOLBF, 0);
3033: if (prime_test(in, out, prime_tests == 0 ? 100 : prime_tests,
3034: generator_wanted, checkpoint,
3035: start_lineno, lines_to_process) != 0)
3036: fatal("modulus screening failed");
1.465 dtucker 3037: if (in != stdin)
3038: (void)fclose(in);
1.464 dtucker 3039: free(checkpoint);
1.376 djm 3040: #else /* WITH_OPENSSL */
3041: fatal("Moduli screening is not supported");
3042: #endif /* WITH_OPENSSL */
3043: }
3044:
1.455 djm 3045: /* Read and confirm a passphrase */
1.381 djm 3046: static char *
1.455 djm 3047: read_check_passphrase(const char *prompt1, const char *prompt2,
3048: const char *retry_prompt)
1.381 djm 3049: {
3050: char *passphrase1, *passphrase2;
3051:
1.455 djm 3052: for (;;) {
3053: passphrase1 = read_passphrase(prompt1, RP_ALLOW_STDIN);
3054: passphrase2 = read_passphrase(prompt2, RP_ALLOW_STDIN);
3055: if (strcmp(passphrase1, passphrase2) == 0) {
1.381 djm 3056: freezero(passphrase2, strlen(passphrase2));
1.455 djm 3057: return passphrase1;
1.381 djm 3058: }
1.455 djm 3059: /* The passphrases do not match. Clear them and retry. */
3060: freezero(passphrase1, strlen(passphrase1));
1.381 djm 3061: freezero(passphrase2, strlen(passphrase2));
1.455 djm 3062: fputs(retry_prompt, stdout);
3063: fputc('\n', stdout);
3064: fflush(stdout);
1.381 djm 3065: }
1.455 djm 3066: /* NOTREACHED */
3067: return NULL;
3068: }
3069:
3070: static char *
3071: private_key_passphrase(void)
3072: {
3073: if (identity_passphrase)
3074: return xstrdup(identity_passphrase);
3075: if (identity_new_passphrase)
3076: return xstrdup(identity_new_passphrase);
3077:
3078: return read_check_passphrase(
3079: "Enter passphrase (empty for no passphrase): ",
3080: "Enter same passphrase again: ",
3081: "Passphrases do not match. Try again.");
1.381 djm 3082: }
3083:
1.439 djm 3084: static char *
3085: sk_suffix(const char *application, const uint8_t *user, size_t userlen)
1.381 djm 3086: {
1.439 djm 3087: char *ret, *cp;
3088: size_t slen, i;
3089:
3090: /* Trim off URL-like preamble */
3091: if (strncmp(application, "ssh://", 6) == 0)
3092: ret = xstrdup(application + 6);
3093: else if (strncmp(application, "ssh:", 4) == 0)
3094: ret = xstrdup(application + 4);
3095: else
3096: ret = xstrdup(application);
3097:
3098: /* Count trailing zeros in user */
3099: for (i = 0; i < userlen; i++) {
3100: if (user[userlen - i - 1] != 0)
3101: break;
3102: }
3103: if (i >= userlen)
3104: return ret; /* user-id was default all-zeros */
3105:
3106: /* Append user-id, escaping non-UTF-8 characters */
3107: slen = userlen - i;
3108: if (asmprintf(&cp, INT_MAX, NULL, "%.*s", (int)slen, user) == -1)
3109: fatal_f("asmprintf failed");
3110: /* Don't emit a user-id that contains path or control characters */
3111: if (strchr(cp, '/') != NULL || strstr(cp, "..") != NULL ||
3112: strchr(cp, '\\') != NULL) {
3113: free(cp);
3114: cp = tohex(user, slen);
3115: }
3116: xextendf(&ret, "_", "%s", cp);
3117: free(cp);
3118: return ret;
1.381 djm 3119: }
3120:
3121: static int
1.382 djm 3122: do_download_sk(const char *skprovider, const char *device)
1.381 djm 3123: {
1.439 djm 3124: struct sshsk_resident_key **srks;
3125: size_t nsrks, i;
1.412 djm 3126: int r, ret = -1;
1.403 djm 3127: char *fp, *pin = NULL, *pass = NULL, *path, *pubpath;
1.381 djm 3128: const char *ext;
1.439 djm 3129: struct sshkey *key;
1.381 djm 3130:
3131: if (skprovider == NULL)
3132: fatal("Cannot download keys without provider");
3133:
1.418 djm 3134: pin = read_passphrase("Enter PIN for authenticator: ", RP_ALLOW_STDIN);
3135: if (!quiet) {
3136: printf("You may need to touch your authenticator "
3137: "to authorize key download.\n");
3138: }
1.439 djm 3139: if ((r = sshsk_load_resident(skprovider, device, pin, 0,
3140: &srks, &nsrks)) != 0) {
1.418 djm 3141: if (pin != NULL)
3142: freezero(pin, strlen(pin));
1.421 djm 3143: error_r(r, "Unable to load resident keys");
1.418 djm 3144: return -1;
1.381 djm 3145: }
1.439 djm 3146: if (nsrks == 0)
1.381 djm 3147: logit("No keys to download");
1.411 djm 3148: if (pin != NULL)
3149: freezero(pin, strlen(pin));
1.381 djm 3150:
1.439 djm 3151: for (i = 0; i < nsrks; i++) {
3152: key = srks[i]->key;
3153: if (key->type != KEY_ECDSA_SK && key->type != KEY_ED25519_SK) {
1.381 djm 3154: error("Unsupported key type %s (%d)",
1.439 djm 3155: sshkey_type(key), key->type);
1.381 djm 3156: continue;
3157: }
1.439 djm 3158: if ((fp = sshkey_fingerprint(key, fingerprint_hash,
3159: SSH_FP_DEFAULT)) == NULL)
1.421 djm 3160: fatal_f("sshkey_fingerprint failed");
3161: debug_f("key %zu: %s %s %s (flags 0x%02x)", i,
1.439 djm 3162: sshkey_type(key), fp, key->sk_application, key->sk_flags);
3163: ext = sk_suffix(key->sk_application,
3164: srks[i]->user_id, srks[i]->user_id_len);
1.381 djm 3165: xasprintf(&path, "id_%s_rk%s%s",
1.439 djm 3166: key->type == KEY_ECDSA_SK ? "ecdsa_sk" : "ed25519_sk",
1.381 djm 3167: *ext == '\0' ? "" : "_", ext);
3168:
3169: /* If the file already exists, ask the user to confirm. */
3170: if (!confirm_overwrite(path)) {
3171: free(path);
3172: break;
3173: }
3174:
3175: /* Save the key with the application string as the comment */
3176: if (pass == NULL)
3177: pass = private_key_passphrase();
1.439 djm 3178: if ((r = sshkey_save_private(key, path, pass,
3179: key->sk_application, private_key_format,
1.381 djm 3180: openssh_format_cipher, rounds)) != 0) {
1.421 djm 3181: error_r(r, "Saving key \"%s\" failed", path);
1.381 djm 3182: free(path);
3183: break;
3184: }
3185: if (!quiet) {
1.439 djm 3186: printf("Saved %s key%s%s to %s\n", sshkey_type(key),
1.381 djm 3187: *ext != '\0' ? " " : "",
1.439 djm 3188: *ext != '\0' ? key->sk_application : "",
1.381 djm 3189: path);
3190: }
3191:
3192: /* Save public key too */
3193: xasprintf(&pubpath, "%s.pub", path);
3194: free(path);
1.439 djm 3195: if ((r = sshkey_save_public(key, pubpath,
3196: key->sk_application)) != 0) {
1.421 djm 3197: error_r(r, "Saving public key \"%s\" failed", pubpath);
1.402 markus 3198: free(pubpath);
1.381 djm 3199: break;
3200: }
3201: free(pubpath);
3202: }
3203:
1.439 djm 3204: if (i >= nsrks)
1.412 djm 3205: ret = 0; /* success */
1.381 djm 3206: if (pass != NULL)
3207: freezero(pass, strlen(pass));
1.439 djm 3208: sshsk_free_resident_keys(srks, nsrks);
1.412 djm 3209: return ret;
1.381 djm 3210: }
3211:
1.376 djm 3212: static void
1.420 djm 3213: save_attestation(struct sshbuf *attest, const char *path)
3214: {
3215: mode_t omask;
3216: int r;
3217:
3218: if (path == NULL)
3219: return; /* nothing to do */
3220: if (attest == NULL || sshbuf_len(attest) == 0)
3221: fatal("Enrollment did not return attestation data");
3222: omask = umask(077);
3223: r = sshbuf_write_file(path, attest);
3224: umask(omask);
3225: if (r != 0)
1.421 djm 3226: fatal_r(r, "Unable to write attestation data \"%s\"", path);
1.420 djm 3227: if (!quiet)
3228: printf("Your FIDO attestation certificate has been saved in "
3229: "%s\n", path);
3230: }
3231:
1.456 djm 3232: static int
3233: confirm_sk_overwrite(const char *application, const char *user)
3234: {
3235: char yesno[3];
3236:
3237: printf("A resident key scoped to '%s' with user id '%s' already "
3238: "exists.\n", application == NULL ? "ssh:" : application,
3239: user == NULL ? "null" : user);
3240: printf("Overwrite key in token (y/n)? ");
3241: fflush(stdout);
3242: if (fgets(yesno, sizeof(yesno), stdin) == NULL)
3243: return 0;
3244: if (yesno[0] != 'y' && yesno[0] != 'Y')
3245: return 0;
3246: return 1;
3247: }
3248:
1.420 djm 3249: static void
1.10 markus 3250: usage(void)
3251: {
1.243 deraadt 3252: fprintf(stderr,
1.414 solene 3253: "usage: ssh-keygen [-q] [-a rounds] [-b bits] [-C comment] [-f output_keyfile]\n"
3254: " [-m format] [-N new_passphrase] [-O option]\n"
1.369 naddy 3255: " [-t dsa | ecdsa | ecdsa-sk | ed25519 | ed25519-sk | rsa]\n"
1.425 dtucker 3256: " [-w provider] [-Z cipher]\n"
1.414 solene 3257: " ssh-keygen -p [-a rounds] [-f keyfile] [-m format] [-N new_passphrase]\n"
1.425 dtucker 3258: " [-P old_passphrase] [-Z cipher]\n"
1.433 dtucker 3259: #ifdef WITH_OPENSSL
1.355 jmc 3260: " ssh-keygen -i [-f input_keyfile] [-m key_format]\n"
3261: " ssh-keygen -e [-f input_keyfile] [-m key_format]\n"
1.434 dtucker 3262: #endif
1.243 deraadt 3263: " ssh-keygen -y [-f input_keyfile]\n"
1.414 solene 3264: " ssh-keygen -c [-a rounds] [-C comment] [-f keyfile] [-P passphrase]\n"
1.265 naddy 3265: " ssh-keygen -l [-v] [-E fingerprint_hash] [-f input_keyfile]\n"
1.302 djm 3266: " ssh-keygen -B [-f input_keyfile]\n");
1.177 markus 3267: #ifdef ENABLE_PKCS11
1.243 deraadt 3268: fprintf(stderr,
3269: " ssh-keygen -D pkcs11\n");
1.177 markus 3270: #endif
1.243 deraadt 3271: fprintf(stderr,
1.352 jmc 3272: " ssh-keygen -F hostname [-lv] [-f known_hosts_file]\n"
1.243 deraadt 3273: " ssh-keygen -H [-f known_hosts_file]\n"
1.414 solene 3274: " ssh-keygen -K [-a rounds] [-w provider]\n"
1.243 deraadt 3275: " ssh-keygen -R hostname [-f known_hosts_file]\n"
1.352 jmc 3276: " ssh-keygen -r hostname [-g] [-f input_keyfile]\n"
1.274 djm 3277: #ifdef WITH_OPENSSL
1.383 naddy 3278: " ssh-keygen -M generate [-O option] output_file\n"
3279: " ssh-keygen -M screen [-f input_file] [-O option] output_file\n"
1.274 djm 3280: #endif
1.355 jmc 3281: " ssh-keygen -I certificate_identity -s ca_key [-hU] [-D pkcs11_provider]\n"
3282: " [-n principals] [-O option] [-V validity_interval]\n"
3283: " [-z serial_number] file ...\n"
1.243 deraadt 3284: " ssh-keygen -L [-f input_keyfile]\n"
1.414 solene 3285: " ssh-keygen -A [-a rounds] [-f prefix_path]\n"
1.243 deraadt 3286: " ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n"
3287: " file ...\n"
1.405 djm 3288: " ssh-keygen -Q [-l] -f krl_file [file ...]\n"
1.388 djm 3289: " ssh-keygen -Y find-principals -s signature_file -f allowed_signers_file\n"
1.442 djm 3290: " ssh-keygen -Y match-principals -I signer_identity -f allowed_signers_file\n"
1.355 jmc 3291: " ssh-keygen -Y check-novalidate -n namespace -s signature_file\n"
1.445 djm 3292: " ssh-keygen -Y sign -f key_file -n namespace file [-O option] ...\n"
1.355 jmc 3293: " ssh-keygen -Y verify -f allowed_signers_file -I signer_identity\n"
1.445 djm 3294: " -n namespace -s signature_file [-r krl_file] [-O option]\n");
1.12 markus 3295: exit(1);
1.10 markus 3296: }
3297:
1.13 deraadt 3298: /*
3299: * Main program for key management.
3300: */
1.2 provos 3301: int
1.156 deraadt 3302: main(int argc, char **argv)
1.1 deraadt 3303: {
1.458 djm 3304: char comment[1024], *passphrase = NULL;
1.274 djm 3305: char *rr_hostname = NULL, *ep, *fp, *ra;
1.252 djm 3306: struct sshkey *private, *public;
1.12 markus 3307: struct passwd *pw;
1.381 djm 3308: int r, opt, type;
1.325 djm 3309: int change_passphrase = 0, change_comment = 0, show_cert = 0;
3310: int find_host = 0, delete_host = 0, hash_hosts = 0;
1.274 djm 3311: int gen_all_hostkeys = 0, gen_krl = 0, update_krl = 0, check_krl = 0;
1.325 djm 3312: int prefer_agent = 0, convert_to = 0, convert_from = 0;
1.326 djm 3313: int print_public = 0, print_generic = 0, cert_serial_autoinc = 0;
1.381 djm 3314: int do_gen_candidates = 0, do_screen_candidates = 0, download_sk = 0;
1.380 djm 3315: unsigned long long cert_serial = 0;
1.375 djm 3316: char *identity_comment = NULL, *ca_key_path = NULL, **opts = NULL;
1.382 djm 3317: char *sk_application = NULL, *sk_device = NULL, *sk_user = NULL;
1.420 djm 3318: char *sk_attestation_path = NULL;
1.395 djm 3319: struct sshbuf *challenge = NULL, *attest = NULL;
1.375 djm 3320: size_t i, nopts = 0;
1.340 dtucker 3321: u_int32_t bits = 0;
1.357 djm 3322: uint8_t sk_flags = SSH_SK_USER_PRESENCE_REQD;
1.274 djm 3323: const char *errstr;
1.325 djm 3324: int log_level = SYSLOG_LEVEL_INFO;
1.344 djm 3325: char *sign_op = NULL;
1.33 markus 3326:
1.12 markus 3327: extern int optind;
3328: extern char *optarg;
1.129 djm 3329:
3330: /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
3331: sanitise_stdfd();
1.12 markus 3332:
1.348 djm 3333: #ifdef WITH_OPENSSL
1.201 djm 3334: OpenSSL_add_all_algorithms();
1.348 djm 3335: #endif
1.156 deraadt 3336: log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
1.294 djm 3337:
3338: setlocale(LC_CTYPE, "");
1.19 markus 3339:
1.14 markus 3340: /* we need this for the home * directory. */
1.12 markus 3341: pw = getpwuid(getuid());
1.269 djm 3342: if (!pw)
3343: fatal("No user exists for uid %lu", (u_long)getuid());
1.428 djm 3344: pw = pwcopy(pw);
1.333 deraadt 3345: if (gethostname(hostname, sizeof(hostname)) == -1)
1.269 djm 3346: fatal("gethostname: %s", strerror(errno));
1.14 markus 3347:
1.357 djm 3348: sk_provider = getenv("SSH_SK_PROVIDER");
3349:
1.381 djm 3350: /* Remaining characters: dGjJSTWx */
3351: while ((opt = getopt(argc, argv, "ABHKLQUXceghiklopquvy"
1.376 djm 3352: "C:D:E:F:I:M:N:O:P:R:V:Y:Z:"
1.380 djm 3353: "a:b:f:g:m:n:r:s:t:w:z:")) != -1) {
1.12 markus 3354: switch (opt) {
1.206 stevesk 3355: case 'A':
3356: gen_all_hostkeys = 1;
3357: break;
1.12 markus 3358: case 'b':
1.340 dtucker 3359: bits = (u_int32_t)strtonum(optarg, 1, UINT32_MAX,
3360: &errstr);
1.125 avsm 3361: if (errstr)
3362: fatal("Bits has bad value %s (%s)",
3363: optarg, errstr);
1.12 markus 3364: break;
1.251 djm 3365: case 'E':
3366: fingerprint_hash = ssh_digest_alg_by_name(optarg);
3367: if (fingerprint_hash == -1)
3368: fatal("Invalid hash algorithm \"%s\"", optarg);
3369: break;
1.119 djm 3370: case 'F':
3371: find_host = 1;
3372: rr_hostname = optarg;
3373: break;
3374: case 'H':
3375: hash_hosts = 1;
3376: break;
1.179 djm 3377: case 'I':
3378: cert_key_id = optarg;
3379: break;
1.119 djm 3380: case 'R':
3381: delete_host = 1;
3382: rr_hostname = optarg;
3383: break;
1.182 djm 3384: case 'L':
3385: show_cert = 1;
3386: break;
1.12 markus 3387: case 'l':
3388: print_fingerprint = 1;
3389: break;
1.49 markus 3390: case 'B':
3391: print_bubblebabble = 1;
3392: break;
1.193 djm 3393: case 'm':
3394: if (strcasecmp(optarg, "RFC4716") == 0 ||
3395: strcasecmp(optarg, "ssh2") == 0) {
3396: convert_format = FMT_RFC4716;
3397: break;
3398: }
3399: if (strcasecmp(optarg, "PKCS8") == 0) {
3400: convert_format = FMT_PKCS8;
1.336 djm 3401: private_key_format = SSHKEY_PRIVATE_PKCS8;
1.193 djm 3402: break;
3403: }
3404: if (strcasecmp(optarg, "PEM") == 0) {
3405: convert_format = FMT_PEM;
1.336 djm 3406: private_key_format = SSHKEY_PRIVATE_PEM;
1.193 djm 3407: break;
3408: }
3409: fatal("Unsupported conversion format \"%s\"", optarg);
1.179 djm 3410: case 'n':
3411: cert_principals = optarg;
3412: break;
1.237 markus 3413: case 'o':
1.319 djm 3414: /* no-op; new format is already the default */
1.237 markus 3415: break;
1.12 markus 3416: case 'p':
3417: change_passphrase = 1;
3418: break;
3419: case 'c':
3420: change_comment = 1;
3421: break;
3422: case 'f':
1.274 djm 3423: if (strlcpy(identity_file, optarg,
3424: sizeof(identity_file)) >= sizeof(identity_file))
1.124 avsm 3425: fatal("Identity filename too long");
1.12 markus 3426: have_identity = 1;
3427: break;
1.105 jakob 3428: case 'g':
3429: print_generic = 1;
3430: break;
1.381 djm 3431: case 'K':
3432: download_sk = 1;
3433: break;
1.12 markus 3434: case 'P':
3435: identity_passphrase = optarg;
3436: break;
3437: case 'N':
3438: identity_new_passphrase = optarg;
3439: break;
1.223 djm 3440: case 'Q':
3441: check_krl = 1;
3442: break;
1.179 djm 3443: case 'O':
1.375 djm 3444: opts = xrecallocarray(opts, nopts, nopts + 1,
3445: sizeof(*opts));
3446: opts[nopts++] = xstrdup(optarg);
1.179 djm 3447: break;
1.237 markus 3448: case 'Z':
1.336 djm 3449: openssh_format_cipher = optarg;
1.425 dtucker 3450: if (cipher_by_name(openssh_format_cipher) == NULL)
3451: fatal("Invalid OpenSSH-format cipher '%s'",
3452: openssh_format_cipher);
1.237 markus 3453: break;
1.12 markus 3454: case 'C':
3455: identity_comment = optarg;
3456: break;
3457: case 'q':
3458: quiet = 1;
1.20 deraadt 3459: break;
1.57 markus 3460: case 'e':
3461: /* export key */
1.193 djm 3462: convert_to = 1;
1.19 markus 3463: break;
1.179 djm 3464: case 'h':
3465: cert_key_type = SSH2_CERT_TYPE_HOST;
1.190 djm 3466: certflags_flags = 0;
1.179 djm 3467: break;
1.223 djm 3468: case 'k':
3469: gen_krl = 1;
3470: break;
1.57 markus 3471: case 'i':
1.19 markus 3472: case 'X':
1.57 markus 3473: /* import key */
1.193 djm 3474: convert_from = 1;
1.19 markus 3475: break;
3476: case 'y':
3477: print_public = 1;
3478: break;
1.179 djm 3479: case 's':
3480: ca_key_path = optarg;
3481: break;
1.33 markus 3482: case 't':
3483: key_type_name = optarg;
3484: break;
1.75 markus 3485: case 'D':
1.177 markus 3486: pkcs11provider = optarg;
1.305 djm 3487: break;
3488: case 'U':
3489: prefer_agent = 1;
1.66 markus 3490: break;
1.223 djm 3491: case 'u':
3492: update_krl = 1;
3493: break;
1.113 djm 3494: case 'v':
3495: if (log_level == SYSLOG_LEVEL_INFO)
3496: log_level = SYSLOG_LEVEL_DEBUG1;
3497: else {
1.117 deraadt 3498: if (log_level >= SYSLOG_LEVEL_DEBUG1 &&
1.113 djm 3499: log_level < SYSLOG_LEVEL_DEBUG3)
3500: log_level++;
3501: }
3502: break;
1.105 jakob 3503: case 'r':
1.119 djm 3504: rr_hostname = optarg;
1.105 jakob 3505: break;
1.107 djm 3506: case 'a':
1.237 markus 3507: rounds = (int)strtonum(optarg, 1, INT_MAX, &errstr);
1.124 avsm 3508: if (errstr)
1.237 markus 3509: fatal("Invalid number: %s (%s)",
1.124 avsm 3510: optarg, errstr);
1.107 djm 3511: break;
1.274 djm 3512: case 'V':
3513: parse_cert_times(optarg);
3514: break;
1.344 djm 3515: case 'Y':
3516: sign_op = optarg;
1.365 djm 3517: break;
1.357 djm 3518: case 'w':
3519: sk_provider = optarg;
3520: break;
1.274 djm 3521: case 'z':
3522: errno = 0;
1.326 djm 3523: if (*optarg == '+') {
3524: cert_serial_autoinc = 1;
3525: optarg++;
3526: }
1.274 djm 3527: cert_serial = strtoull(optarg, &ep, 10);
3528: if (*optarg < '0' || *optarg > '9' || *ep != '\0' ||
3529: (errno == ERANGE && cert_serial == ULLONG_MAX))
3530: fatal("Invalid serial number \"%s\"", optarg);
1.107 djm 3531: break;
1.274 djm 3532: case 'M':
1.376 djm 3533: if (strcmp(optarg, "generate") == 0)
3534: do_gen_candidates = 1;
3535: else if (strcmp(optarg, "screen") == 0)
3536: do_screen_candidates = 1;
3537: else
3538: fatal("Unsupported moduli option %s", optarg);
1.179 djm 3539: break;
1.12 markus 3540: default:
3541: usage();
3542: }
3543: }
1.364 djm 3544:
3545: if (sk_provider == NULL)
3546: sk_provider = "internal";
1.113 djm 3547:
3548: /* reinit */
1.156 deraadt 3549: log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1);
1.113 djm 3550:
1.179 djm 3551: argv += optind;
3552: argc -= optind;
1.344 djm 3553:
3554: if (sign_op != NULL) {
1.388 djm 3555: if (strncmp(sign_op, "find-principals", 15) == 0) {
1.386 djm 3556: if (ca_key_path == NULL) {
1.388 djm 3557: error("Too few arguments for find-principals:"
1.429 djm 3558: "missing signature file");
1.386 djm 3559: exit(1);
3560: }
3561: if (!have_identity) {
1.388 djm 3562: error("Too few arguments for find-principals:"
1.429 djm 3563: "missing allowed keys file");
1.386 djm 3564: exit(1);
3565: }
1.432 djm 3566: return sig_find_principals(ca_key_path, identity_file,
1.441 djm 3567: opts, nopts);
3568: } else if (strncmp(sign_op, "match-principals", 16) == 0) {
3569: if (!have_identity) {
3570: error("Too few arguments for match-principals:"
3571: "missing allowed keys file");
3572: exit(1);
3573: }
3574: if (cert_key_id == NULL) {
3575: error("Too few arguments for match-principals: "
3576: "missing principal ID");
3577: exit(1);
3578: }
3579: return sig_match_principals(identity_file, cert_key_id,
1.432 djm 3580: opts, nopts);
1.391 djm 3581: } else if (strncmp(sign_op, "sign", 4) == 0) {
1.447 djm 3582: /* NB. cert_principals is actually namespace, via -n */
1.391 djm 3583: if (cert_principals == NULL ||
3584: *cert_principals == '\0') {
3585: error("Too few arguments for sign: "
3586: "missing namespace");
3587: exit(1);
3588: }
1.344 djm 3589: if (!have_identity) {
3590: error("Too few arguments for sign: "
3591: "missing key");
3592: exit(1);
3593: }
1.386 djm 3594: return sig_sign(identity_file, cert_principals,
1.452 djm 3595: prefer_agent, argc, argv, opts, nopts);
1.350 djm 3596: } else if (strncmp(sign_op, "check-novalidate", 16) == 0) {
1.450 djm 3597: /* NB. cert_principals is actually namespace, via -n */
1.449 djm 3598: if (cert_principals == NULL ||
3599: *cert_principals == '\0') {
3600: error("Too few arguments for check-novalidate: "
3601: "missing namespace");
3602: exit(1);
3603: }
1.350 djm 3604: if (ca_key_path == NULL) {
3605: error("Too few arguments for check-novalidate: "
1.429 djm 3606: "missing signature file");
1.350 djm 3607: exit(1);
3608: }
1.386 djm 3609: return sig_verify(ca_key_path, cert_principals,
1.432 djm 3610: NULL, NULL, NULL, opts, nopts);
1.344 djm 3611: } else if (strncmp(sign_op, "verify", 6) == 0) {
1.447 djm 3612: /* NB. cert_principals is actually namespace, via -n */
1.391 djm 3613: if (cert_principals == NULL ||
3614: *cert_principals == '\0') {
3615: error("Too few arguments for verify: "
1.447 djm 3616: "missing namespace");
1.391 djm 3617: exit(1);
3618: }
1.344 djm 3619: if (ca_key_path == NULL) {
3620: error("Too few arguments for verify: "
3621: "missing signature file");
3622: exit(1);
3623: }
3624: if (!have_identity) {
3625: error("Too few arguments for sign: "
3626: "missing allowed keys file");
3627: exit(1);
3628: }
3629: if (cert_key_id == NULL) {
3630: error("Too few arguments for verify: "
1.447 djm 3631: "missing principal identity");
1.344 djm 3632: exit(1);
3633: }
1.386 djm 3634: return sig_verify(ca_key_path, cert_principals,
1.432 djm 3635: cert_key_id, identity_file, rr_hostname,
3636: opts, nopts);
1.344 djm 3637: }
1.391 djm 3638: error("Unsupported operation for -Y: \"%s\"", sign_op);
1.344 djm 3639: usage();
3640: /* NOTREACHED */
3641: }
1.179 djm 3642:
3643: if (ca_key_path != NULL) {
1.223 djm 3644: if (argc < 1 && !gen_krl) {
1.269 djm 3645: error("Too few arguments.");
1.179 djm 3646: usage();
3647: }
1.376 djm 3648: } else if (argc > 0 && !gen_krl && !check_krl &&
3649: !do_gen_candidates && !do_screen_candidates) {
1.269 djm 3650: error("Too many arguments.");
1.87 djm 3651: usage();
3652: }
1.12 markus 3653: if (change_passphrase && change_comment) {
1.269 djm 3654: error("Can only have one of -p and -c.");
1.166 djm 3655: usage();
3656: }
3657: if (print_fingerprint && (delete_host || hash_hosts)) {
1.269 djm 3658: error("Cannot use -l with -H or -R.");
1.12 markus 3659: usage();
1.223 djm 3660: }
1.376 djm 3661: if (gen_krl) {
1.325 djm 3662: do_gen_krl(pw, update_krl, ca_key_path,
3663: cert_serial, identity_comment, argc, argv);
1.223 djm 3664: return (0);
3665: }
3666: if (check_krl) {
1.405 djm 3667: do_check_krl(pw, print_fingerprint, argc, argv);
1.223 djm 3668: return (0);
1.179 djm 3669: }
3670: if (ca_key_path != NULL) {
3671: if (cert_key_id == NULL)
3672: fatal("Must specify key id (-I) when certifying");
1.375 djm 3673: for (i = 0; i < nopts; i++)
3674: add_cert_option(opts[i]);
1.326 djm 3675: do_ca_sign(pw, ca_key_path, prefer_agent,
3676: cert_serial, cert_serial_autoinc, argc, argv);
1.12 markus 3677: }
1.182 djm 3678: if (show_cert)
3679: do_show_cert(pw);
1.325 djm 3680: if (delete_host || hash_hosts || find_host) {
3681: do_known_hosts(pw, rr_hostname, find_host,
3682: delete_host, hash_hosts);
3683: }
1.221 djm 3684: if (pkcs11provider != NULL)
3685: do_download(pw);
1.382 djm 3686: if (download_sk) {
3687: for (i = 0; i < nopts; i++) {
3688: if (strncasecmp(opts[i], "device=", 7) == 0) {
3689: sk_device = xstrdup(opts[i] + 7);
3690: } else {
3691: fatal("Option \"%s\" is unsupported for "
3692: "FIDO authenticator download", opts[i]);
3693: }
3694: }
3695: return do_download_sk(sk_provider, sk_device);
3696: }
1.49 markus 3697: if (print_fingerprint || print_bubblebabble)
1.12 markus 3698: do_fingerprint(pw);
3699: if (change_passphrase)
3700: do_change_passphrase(pw);
3701: if (change_comment)
1.325 djm 3702: do_change_comment(pw, identity_comment);
1.246 markus 3703: #ifdef WITH_OPENSSL
1.193 djm 3704: if (convert_to)
3705: do_convert_to(pw);
3706: if (convert_from)
3707: do_convert_from(pw);
1.349 djm 3708: #else /* WITH_OPENSSL */
3709: if (convert_to || convert_from)
3710: fatal("key conversion disabled at compile time");
3711: #endif /* WITH_OPENSSL */
1.19 markus 3712: if (print_public)
3713: do_print_public(pw);
1.119 djm 3714: if (rr_hostname != NULL) {
1.138 jakob 3715: unsigned int n = 0;
3716:
3717: if (have_identity) {
1.325 djm 3718: n = do_print_resource_record(pw, identity_file,
1.462 djm 3719: rr_hostname, print_generic, opts, nopts);
1.269 djm 3720: if (n == 0)
3721: fatal("%s: %s", identity_file, strerror(errno));
1.138 jakob 3722: exit(0);
3723: } else {
3724:
3725: n += do_print_resource_record(pw,
1.325 djm 3726: _PATH_HOST_RSA_KEY_FILE, rr_hostname,
1.462 djm 3727: print_generic, opts, nopts);
1.138 jakob 3728: n += do_print_resource_record(pw,
1.325 djm 3729: _PATH_HOST_DSA_KEY_FILE, rr_hostname,
1.462 djm 3730: print_generic, opts, nopts);
1.214 djm 3731: n += do_print_resource_record(pw,
1.325 djm 3732: _PATH_HOST_ECDSA_KEY_FILE, rr_hostname,
1.462 djm 3733: print_generic, opts, nopts);
1.244 logan 3734: n += do_print_resource_record(pw,
1.325 djm 3735: _PATH_HOST_ED25519_KEY_FILE, rr_hostname,
1.462 djm 3736: print_generic, opts, nopts);
1.313 markus 3737: n += do_print_resource_record(pw,
1.325 djm 3738: _PATH_HOST_XMSS_KEY_FILE, rr_hostname,
1.462 djm 3739: print_generic, opts, nopts);
1.138 jakob 3740: if (n == 0)
3741: fatal("no keys found.");
3742: exit(0);
3743: }
1.105 jakob 3744: }
1.107 djm 3745:
1.376 djm 3746: if (do_gen_candidates || do_screen_candidates) {
3747: if (argc <= 0)
3748: fatal("No output file specified");
3749: else if (argc > 1)
3750: fatal("Too many output files specified");
3751: }
1.107 djm 3752: if (do_gen_candidates) {
1.376 djm 3753: do_moduli_gen(argv[0], opts, nopts);
3754: return 0;
1.107 djm 3755: }
3756: if (do_screen_candidates) {
1.376 djm 3757: do_moduli_screen(argv[0], opts, nopts);
3758: return 0;
1.75 markus 3759: }
1.12 markus 3760:
1.206 stevesk 3761: if (gen_all_hostkeys) {
3762: do_gen_all_hostkeys(pw);
3763: return (0);
3764: }
3765:
1.133 djm 3766: if (key_type_name == NULL)
1.273 djm 3767: key_type_name = DEFAULT_KEY_TYPE_NAME;
1.133 djm 3768:
1.252 djm 3769: type = sshkey_type_from_name(key_type_name);
1.255 djm 3770: type_bits_valid(type, key_type_name, &bits);
1.206 stevesk 3771:
1.33 markus 3772: if (!quiet)
1.252 djm 3773: printf("Generating public/private %s key pair.\n",
3774: key_type_name);
1.362 markus 3775: switch (type) {
3776: case KEY_ECDSA_SK:
3777: case KEY_ED25519_SK:
1.380 djm 3778: for (i = 0; i < nopts; i++) {
3779: if (strcasecmp(opts[i], "no-touch-required") == 0) {
3780: sk_flags &= ~SSH_SK_USER_PRESENCE_REQD;
1.416 djm 3781: } else if (strcasecmp(opts[i], "verify-required") == 0) {
3782: sk_flags |= SSH_SK_USER_VERIFICATION_REQD;
1.380 djm 3783: } else if (strcasecmp(opts[i], "resident") == 0) {
3784: sk_flags |= SSH_SK_RESIDENT_KEY;
1.382 djm 3785: } else if (strncasecmp(opts[i], "device=", 7) == 0) {
3786: sk_device = xstrdup(opts[i] + 7);
3787: } else if (strncasecmp(opts[i], "user=", 5) == 0) {
3788: sk_user = xstrdup(opts[i] + 5);
1.395 djm 3789: } else if (strncasecmp(opts[i], "challenge=", 10) == 0) {
3790: if ((r = sshbuf_load_file(opts[i] + 10,
3791: &challenge)) != 0) {
1.421 djm 3792: fatal_r(r, "Unable to load FIDO "
3793: "enrollment challenge \"%s\"",
3794: opts[i] + 10);
1.395 djm 3795: }
3796: } else if (strncasecmp(opts[i],
3797: "write-attestation=", 18) == 0) {
1.420 djm 3798: sk_attestation_path = opts[i] + 18;
1.382 djm 3799: } else if (strncasecmp(opts[i],
3800: "application=", 12) == 0) {
3801: sk_application = xstrdup(opts[i] + 12);
1.396 djm 3802: if (strncmp(sk_application, "ssh:", 4) != 0) {
3803: fatal("FIDO application string must "
3804: "begin with \"ssh:\"");
3805: }
1.380 djm 3806: } else {
3807: fatal("Option \"%s\" is unsupported for "
3808: "FIDO authenticator enrollment", opts[i]);
3809: }
3810: }
1.395 djm 3811: if ((attest = sshbuf_new()) == NULL)
3812: fatal("sshbuf_new failed");
1.457 djm 3813: r = 0;
3814: for (i = 0 ;;) {
3815: if (!quiet) {
3816: printf("You may need to touch your "
3817: "authenticator%s to authorize key "
3818: "generation.\n",
3819: r == 0 ? "" : " again");
3820: }
1.379 djm 3821: fflush(stdout);
1.382 djm 3822: r = sshsk_enroll(type, sk_provider, sk_device,
3823: sk_application == NULL ? "ssh:" : sk_application,
1.395 djm 3824: sk_user, sk_flags, passphrase, challenge,
3825: &private, attest);
1.379 djm 3826: if (r == 0)
3827: break;
1.456 djm 3828: if (r == SSH_ERR_KEY_BAD_PERMISSIONS &&
3829: (sk_flags & SSH_SK_RESIDENT_KEY) != 0 &&
3830: (sk_flags & SSH_SK_FORCE_OPERATION) == 0 &&
3831: confirm_sk_overwrite(sk_application, sk_user)) {
3832: sk_flags |= SSH_SK_FORCE_OPERATION;
3833: continue;
3834: }
1.379 djm 3835: if (r != SSH_ERR_KEY_WRONG_PASSPHRASE)
1.421 djm 3836: fatal_r(r, "Key enrollment failed");
1.418 djm 3837: else if (passphrase != NULL) {
1.398 djm 3838: error("PIN incorrect");
1.381 djm 3839: freezero(passphrase, strlen(passphrase));
1.398 djm 3840: passphrase = NULL;
3841: }
1.457 djm 3842: if (++i >= 3)
1.398 djm 3843: fatal("Too many incorrect PINs");
1.397 naddy 3844: passphrase = read_passphrase("Enter PIN for "
3845: "authenticator: ", RP_ALLOW_STDIN);
1.373 djm 3846: }
1.398 djm 3847: if (passphrase != NULL) {
1.381 djm 3848: freezero(passphrase, strlen(passphrase));
1.398 djm 3849: passphrase = NULL;
3850: }
1.362 markus 3851: break;
3852: default:
3853: if ((r = sshkey_generate(type, bits, &private)) != 0)
3854: fatal("sshkey_generate failed");
3855: break;
3856: }
1.269 djm 3857: if ((r = sshkey_from_private(private, &public)) != 0)
1.421 djm 3858: fatal_r(r, "sshkey_from_private");
1.12 markus 3859:
3860: if (!have_identity)
3861: ask_filename(pw, "Enter file in which to save the key");
3862:
1.132 djm 3863: /* Create ~/.ssh directory if it doesn't already exist. */
1.413 dtucker 3864: hostfile_create_user_ssh_dir(identity_file, !quiet);
3865:
1.12 markus 3866: /* If the file already exists, ask the user to confirm. */
1.343 djm 3867: if (!confirm_overwrite(identity_file))
3868: exit(1);
1.12 markus 3869:
1.381 djm 3870: /* Determine the passphrase for the private key */
3871: passphrase = private_key_passphrase();
1.12 markus 3872: if (identity_comment) {
3873: strlcpy(comment, identity_comment, sizeof(comment));
3874: } else {
1.172 stevesk 3875: /* Create default comment field for the passphrase. */
1.12 markus 3876: snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
3877: }
3878:
3879: /* Save the key with the given passphrase and comment. */
1.381 djm 3880: if ((r = sshkey_save_private(private, identity_file, passphrase,
1.336 djm 3881: comment, private_key_format, openssh_format_cipher, rounds)) != 0) {
1.421 djm 3882: error_r(r, "Saving key \"%s\" failed", identity_file);
1.381 djm 3883: freezero(passphrase, strlen(passphrase));
1.12 markus 3884: exit(1);
3885: }
1.381 djm 3886: freezero(passphrase, strlen(passphrase));
1.252 djm 3887: sshkey_free(private);
1.12 markus 3888:
1.381 djm 3889: if (!quiet) {
1.387 djm 3890: printf("Your identification has been saved in %s\n",
1.381 djm 3891: identity_file);
3892: }
1.12 markus 3893:
3894: strlcat(identity_file, ".pub", sizeof(identity_file));
1.421 djm 3895: if ((r = sshkey_save_public(public, identity_file, comment)) != 0)
3896: fatal_r(r, "Unable to save public key to %s", identity_file);
1.12 markus 3897:
3898: if (!quiet) {
1.259 djm 3899: fp = sshkey_fingerprint(public, fingerprint_hash,
1.251 djm 3900: SSH_FP_DEFAULT);
1.259 djm 3901: ra = sshkey_fingerprint(public, fingerprint_hash,
1.167 grunk 3902: SSH_FP_RANDOMART);
1.259 djm 3903: if (fp == NULL || ra == NULL)
3904: fatal("sshkey_fingerprint failed");
1.387 djm 3905: printf("Your public key has been saved in %s\n",
1.19 markus 3906: identity_file);
1.12 markus 3907: printf("The key fingerprint is:\n");
1.50 markus 3908: printf("%s %s\n", fp, comment);
1.167 grunk 3909: printf("The key's randomart image is:\n");
3910: printf("%s\n", ra);
1.227 djm 3911: free(ra);
3912: free(fp);
1.12 markus 3913: }
1.19 markus 3914:
1.420 djm 3915: if (sk_attestation_path != NULL)
3916: save_attestation(attest, sk_attestation_path);
3917:
1.395 djm 3918: sshbuf_free(attest);
1.252 djm 3919: sshkey_free(public);
1.395 djm 3920:
1.12 markus 3921: exit(0);
1.1 deraadt 3922: }