1263970Sdes/* $OpenBSD: ssh-keygen.c,v 1.241 2014/02/05 20:13:25 naddy Exp $ */ 257429Smarkm/* 357429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi> 457429Smarkm * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 557429Smarkm * All rights reserved 657429Smarkm * Identity and host key generation and maintenance. 765668Skris * 865668Skris * As far as I am concerned, the code I have written for this software 965668Skris * can be used freely for any purpose. Any derived versions of this 1065668Skris * software must be clearly marked as such, and if the derived work is 1165668Skris * incompatible with the protocol description in the RFC file, it must be 1265668Skris * called by a name other than "ssh" or "Secure Shell". 1357429Smarkm */ 1457429Smarkm 1557429Smarkm#include "includes.h" 1657429Smarkm 17162852Sdes#include <sys/types.h> 18162852Sdes#include <sys/socket.h> 19162852Sdes#include <sys/stat.h> 20162852Sdes#include <sys/param.h> 21162852Sdes 2260573Skris#include <openssl/evp.h> 2360573Skris#include <openssl/pem.h> 24181111Sdes#include "openbsd-compat/openssl-compat.h" 2560573Skris 26162852Sdes#include <errno.h> 27162852Sdes#include <fcntl.h> 28162852Sdes#include <netdb.h> 29162852Sdes#ifdef HAVE_PATHS_H 30162852Sdes# include <paths.h> 31162852Sdes#endif 32162852Sdes#include <pwd.h> 33162852Sdes#include <stdarg.h> 34162852Sdes#include <stdio.h> 35162852Sdes#include <stdlib.h> 36162852Sdes#include <string.h> 37162852Sdes#include <unistd.h> 38162852Sdes 3957429Smarkm#include "xmalloc.h" 4060573Skris#include "key.h" 4160573Skris#include "rsa.h" 4260573Skris#include "authfile.h" 4360573Skris#include "uuencode.h" 4469587Sgreen#include "buffer.h" 4576259Sgreen#include "pathnames.h" 4676259Sgreen#include "log.h" 47137015Sdes#include "misc.h" 48146998Sdes#include "match.h" 49146998Sdes#include "hostfile.h" 50162852Sdes#include "dns.h" 51251135Sdes#include "ssh.h" 52204917Sdes#include "ssh2.h" 53204917Sdes#include "ssh-pkcs11.h" 54251135Sdes#include "atomicio.h" 55251135Sdes#include "krl.h" 5692555Sdes 57157016Sdes/* Number of bits in the RSA/DSA key. This value can be set on the command line. */ 58157016Sdes#define DEFAULT_BITS 2048 59157016Sdes#define DEFAULT_BITS_DSA 1024 60221420Sdes#define DEFAULT_BITS_ECDSA 256 61157016Sdesu_int32_t bits = 0; 6257429Smarkm 6357429Smarkm/* 6457429Smarkm * Flag indicating that we just want to change the passphrase. This can be 6557429Smarkm * set on the command line. 6657429Smarkm */ 6757429Smarkmint change_passphrase = 0; 6857429Smarkm 6957429Smarkm/* 7057429Smarkm * Flag indicating that we just want to change the comment. This can be set 7157429Smarkm * on the command line. 7257429Smarkm */ 7357429Smarkmint change_comment = 0; 7457429Smarkm 7557429Smarkmint quiet = 0; 7657429Smarkm 77181111Sdesint log_level = SYSLOG_LEVEL_INFO; 78181111Sdes 79146998Sdes/* Flag indicating that we want to hash a known_hosts file */ 80146998Sdesint hash_hosts = 0; 81146998Sdes/* Flag indicating that we want lookup a host in known_hosts file */ 82146998Sdesint find_host = 0; 83146998Sdes/* Flag indicating that we want to delete a host from a known_hosts file */ 84146998Sdesint delete_host = 0; 85146998Sdes 86204917Sdes/* Flag indicating that we want to show the contents of a certificate */ 87204917Sdesint show_cert = 0; 88204917Sdes 8957429Smarkm/* Flag indicating that we just want to see the key fingerprint */ 9057429Smarkmint print_fingerprint = 0; 9176259Sgreenint print_bubblebabble = 0; 9257429Smarkm 9357429Smarkm/* The identity file name, given on the command line or entered by the user. */ 9457429Smarkmchar identity_file[1024]; 9557429Smarkmint have_identity = 0; 9657429Smarkm 9757429Smarkm/* This is set to the passphrase if given on the command line. */ 9857429Smarkmchar *identity_passphrase = NULL; 9957429Smarkm 10057429Smarkm/* This is set to the new passphrase if given on the command line. */ 10157429Smarkmchar *identity_new_passphrase = NULL; 10257429Smarkm 10357429Smarkm/* This is set to the new comment if given on the command line. */ 10457429Smarkmchar *identity_comment = NULL; 10557429Smarkm 106204917Sdes/* Path to CA key when certifying keys. */ 107204917Sdeschar *ca_key_path = NULL; 108204917Sdes 109215116Sdes/* Certificate serial number */ 110251135Sdesunsigned long long cert_serial = 0; 111215116Sdes 112204917Sdes/* Key type when certifying */ 113204917Sdesu_int cert_key_type = SSH2_CERT_TYPE_USER; 114204917Sdes 115204917Sdes/* "key ID" of signed key */ 116204917Sdeschar *cert_key_id = NULL; 117204917Sdes 118204917Sdes/* Comma-separated list of principal names for certifying keys */ 119204917Sdeschar *cert_principals = NULL; 120204917Sdes 121204917Sdes/* Validity period for certificates */ 122204917Sdesu_int64_t cert_valid_from = 0; 123204917Sdesu_int64_t cert_valid_to = ~0ULL; 124204917Sdes 125215116Sdes/* Certificate options */ 126215116Sdes#define CERTOPT_X_FWD (1) 127215116Sdes#define CERTOPT_AGENT_FWD (1<<1) 128215116Sdes#define CERTOPT_PORT_FWD (1<<2) 129215116Sdes#define CERTOPT_PTY (1<<3) 130215116Sdes#define CERTOPT_USER_RC (1<<4) 131215116Sdes#define CERTOPT_DEFAULT (CERTOPT_X_FWD|CERTOPT_AGENT_FWD| \ 132215116Sdes CERTOPT_PORT_FWD|CERTOPT_PTY|CERTOPT_USER_RC) 133215116Sdesu_int32_t certflags_flags = CERTOPT_DEFAULT; 134215116Sdeschar *certflags_command = NULL; 135215116Sdeschar *certflags_src_addr = NULL; 136204917Sdes 137215116Sdes/* Conversion to/from various formats */ 138215116Sdesint convert_to = 0; 139215116Sdesint convert_from = 0; 140215116Sdesenum { 141215116Sdes FMT_RFC4716, 142215116Sdes FMT_PKCS8, 143215116Sdes FMT_PEM 144215116Sdes} convert_format = FMT_RFC4716; 14560573Skrisint print_public = 0; 146124208Sdesint print_generic = 0; 14760573Skris 14892555Sdeschar *key_type_name = NULL; 14976259Sgreen 150215116Sdes/* Load key from this PKCS#11 provider */ 151215116Sdeschar *pkcs11provider = NULL; 152215116Sdes 153263970Sdes/* Use new OpenSSH private key format when writing SSH2 keys instead of PEM */ 154263970Sdesint use_new_format = 0; 155263970Sdes 156263970Sdes/* Cipher for new-format private keys */ 157263970Sdeschar *new_format_cipher = NULL; 158263970Sdes 159263970Sdes/* 160263970Sdes * Number of KDF rounds to derive new format keys / 161263970Sdes * number of primality trials when screening moduli. 162263970Sdes */ 163263970Sdesint rounds = 0; 164263970Sdes 16557429Smarkm/* argv0 */ 16657429Smarkmextern char *__progname; 16757429Smarkm 16860573Skrischar hostname[MAXHOSTNAMELEN]; 16960573Skris 170137015Sdes/* moduli.c */ 171149749Sdesint gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *); 172247485Sdesint prime_test(FILE *, FILE *, u_int32_t, u_int32_t, char *, unsigned long, 173247485Sdes unsigned long); 174137015Sdes 17592555Sdesstatic void 176247485Sdestype_bits_valid(int type, u_int32_t *bitsp) 177247485Sdes{ 178247485Sdes u_int maxbits; 179247485Sdes 180247485Sdes if (type == KEY_UNSPEC) { 181247485Sdes fprintf(stderr, "unknown key type %s\n", key_type_name); 182247485Sdes exit(1); 183247485Sdes } 184247485Sdes if (*bitsp == 0) { 185247485Sdes if (type == KEY_DSA) 186247485Sdes *bitsp = DEFAULT_BITS_DSA; 187247485Sdes else if (type == KEY_ECDSA) 188247485Sdes *bitsp = DEFAULT_BITS_ECDSA; 189247485Sdes else 190247485Sdes *bitsp = DEFAULT_BITS; 191247485Sdes } 192247485Sdes maxbits = (type == KEY_DSA) ? 193247485Sdes OPENSSL_DSA_MAX_MODULUS_BITS : OPENSSL_RSA_MAX_MODULUS_BITS; 194247485Sdes if (*bitsp > maxbits) { 195247485Sdes fprintf(stderr, "key bits exceeds maximum %d\n", maxbits); 196247485Sdes exit(1); 197247485Sdes } 198247485Sdes if (type == KEY_DSA && *bitsp != 1024) 199247485Sdes fatal("DSA keys must be 1024 bits"); 200263970Sdes else if (type != KEY_ECDSA && type != KEY_ED25519 && *bitsp < 768) 201247485Sdes fatal("Key must at least be 768 bits"); 202247485Sdes else if (type == KEY_ECDSA && key_ecdsa_bits_to_nid(*bitsp) == -1) 203247485Sdes fatal("Invalid ECDSA key length - valid lengths are " 204247485Sdes "256, 384 or 521 bits"); 205247485Sdes} 206247485Sdes 207247485Sdesstatic void 20857429Smarkmask_filename(struct passwd *pw, const char *prompt) 20957429Smarkm{ 21057429Smarkm char buf[1024]; 21176259Sgreen char *name = NULL; 21276259Sgreen 21392555Sdes if (key_type_name == NULL) 21476259Sgreen name = _PATH_SSH_CLIENT_ID_RSA; 215162852Sdes else { 21692555Sdes switch (key_type_from_name(key_type_name)) { 21792555Sdes case KEY_RSA1: 21892555Sdes name = _PATH_SSH_CLIENT_IDENTITY; 21992555Sdes break; 220215116Sdes case KEY_DSA_CERT: 221215116Sdes case KEY_DSA_CERT_V00: 22292555Sdes case KEY_DSA: 22392555Sdes name = _PATH_SSH_CLIENT_ID_DSA; 22492555Sdes break; 225221420Sdes#ifdef OPENSSL_HAS_ECC 226221420Sdes case KEY_ECDSA_CERT: 227221420Sdes case KEY_ECDSA: 228221420Sdes name = _PATH_SSH_CLIENT_ID_ECDSA; 229221420Sdes break; 230221420Sdes#endif 231215116Sdes case KEY_RSA_CERT: 232215116Sdes case KEY_RSA_CERT_V00: 23392555Sdes case KEY_RSA: 23492555Sdes name = _PATH_SSH_CLIENT_ID_RSA; 23592555Sdes break; 236263970Sdes case KEY_ED25519: 237263970Sdes case KEY_ED25519_CERT: 238263970Sdes name = _PATH_SSH_CLIENT_ID_ED25519; 239263970Sdes break; 24092555Sdes default: 241192595Sdes fprintf(stderr, "bad key type\n"); 24292555Sdes exit(1); 24392555Sdes break; 24492555Sdes } 245162852Sdes } 24676259Sgreen snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name); 24776259Sgreen fprintf(stderr, "%s (%s): ", prompt, identity_file); 24857429Smarkm if (fgets(buf, sizeof(buf), stdin) == NULL) 24957429Smarkm exit(1); 250181111Sdes buf[strcspn(buf, "\n")] = '\0'; 25157429Smarkm if (strcmp(buf, "") != 0) 25257429Smarkm strlcpy(identity_file, buf, sizeof(identity_file)); 25357429Smarkm have_identity = 1; 25457429Smarkm} 25557429Smarkm 25692555Sdesstatic Key * 25792555Sdesload_identity(char *filename) 25860573Skris{ 25976259Sgreen char *pass; 26076259Sgreen Key *prv; 26176259Sgreen 26276259Sgreen prv = key_load_private(filename, "", NULL); 26376259Sgreen if (prv == NULL) { 26492555Sdes if (identity_passphrase) 26592555Sdes pass = xstrdup(identity_passphrase); 26692555Sdes else 26792555Sdes pass = read_passphrase("Enter passphrase: ", 26892555Sdes RP_ALLOW_STDIN); 26976259Sgreen prv = key_load_private(filename, pass, NULL); 270263970Sdes explicit_bzero(pass, strlen(pass)); 271263970Sdes free(pass); 27260573Skris } 27376259Sgreen return prv; 27460573Skris} 27560573Skris 27669587Sgreen#define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----" 27798675Sdes#define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----" 27869587Sgreen#define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----" 27976259Sgreen#define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb 28060573Skris 28192555Sdesstatic void 282215116Sdesdo_convert_to_ssh2(struct passwd *pw, Key *k) 28360573Skris{ 28492555Sdes u_int len; 28576259Sgreen u_char *blob; 286204917Sdes char comment[61]; 28760573Skris 288247485Sdes if (k->type == KEY_RSA1) { 289247485Sdes fprintf(stderr, "version 1 keys are not supported\n"); 290247485Sdes exit(1); 291247485Sdes } 29292555Sdes if (key_to_blob(k, &blob, &len) <= 0) { 29392555Sdes fprintf(stderr, "key_to_blob failed\n"); 29492555Sdes exit(1); 29592555Sdes } 296204917Sdes /* Comment + surrounds must fit into 72 chars (RFC 4716 sec 3.3) */ 297204917Sdes snprintf(comment, sizeof(comment), 298204917Sdes "%u-bit %s, converted by %s@%s from OpenSSH", 29969587Sgreen key_size(k), key_type(k), 30060573Skris pw->pw_name, hostname); 301204917Sdes 302204917Sdes fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN); 303204917Sdes fprintf(stdout, "Comment: \"%s\"\n", comment); 30460573Skris dump_base64(stdout, blob, len); 30569587Sgreen fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END); 30660573Skris key_free(k); 307263970Sdes free(blob); 30860573Skris exit(0); 30960573Skris} 31060573Skris 31192555Sdesstatic void 312215116Sdesdo_convert_to_pkcs8(Key *k) 313215116Sdes{ 314215116Sdes switch (key_type_plain(k->type)) { 315247485Sdes case KEY_RSA1: 316215116Sdes case KEY_RSA: 317215116Sdes if (!PEM_write_RSA_PUBKEY(stdout, k->rsa)) 318215116Sdes fatal("PEM_write_RSA_PUBKEY failed"); 319215116Sdes break; 320215116Sdes case KEY_DSA: 321215116Sdes if (!PEM_write_DSA_PUBKEY(stdout, k->dsa)) 322215116Sdes fatal("PEM_write_DSA_PUBKEY failed"); 323215116Sdes break; 324221420Sdes#ifdef OPENSSL_HAS_ECC 325221420Sdes case KEY_ECDSA: 326221420Sdes if (!PEM_write_EC_PUBKEY(stdout, k->ecdsa)) 327221420Sdes fatal("PEM_write_EC_PUBKEY failed"); 328221420Sdes break; 329221420Sdes#endif 330215116Sdes default: 331215116Sdes fatal("%s: unsupported key type %s", __func__, key_type(k)); 332215116Sdes } 333215116Sdes exit(0); 334215116Sdes} 335215116Sdes 336215116Sdesstatic void 337215116Sdesdo_convert_to_pem(Key *k) 338215116Sdes{ 339215116Sdes switch (key_type_plain(k->type)) { 340247485Sdes case KEY_RSA1: 341215116Sdes case KEY_RSA: 342215116Sdes if (!PEM_write_RSAPublicKey(stdout, k->rsa)) 343215116Sdes fatal("PEM_write_RSAPublicKey failed"); 344215116Sdes break; 345215116Sdes#if notyet /* OpenSSH 0.9.8 lacks this function */ 346215116Sdes case KEY_DSA: 347215116Sdes if (!PEM_write_DSAPublicKey(stdout, k->dsa)) 348215116Sdes fatal("PEM_write_DSAPublicKey failed"); 349215116Sdes break; 350215116Sdes#endif 351221420Sdes /* XXX ECDSA? */ 352215116Sdes default: 353215116Sdes fatal("%s: unsupported key type %s", __func__, key_type(k)); 354215116Sdes } 355215116Sdes exit(0); 356215116Sdes} 357215116Sdes 358215116Sdesstatic void 359215116Sdesdo_convert_to(struct passwd *pw) 360215116Sdes{ 361215116Sdes Key *k; 362215116Sdes struct stat st; 363215116Sdes 364215116Sdes if (!have_identity) 365215116Sdes ask_filename(pw, "Enter file in which the key is"); 366215116Sdes if (stat(identity_file, &st) < 0) 367215116Sdes fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); 368215116Sdes if ((k = key_load_public(identity_file, NULL)) == NULL) { 369215116Sdes if ((k = load_identity(identity_file)) == NULL) { 370215116Sdes fprintf(stderr, "load failed\n"); 371215116Sdes exit(1); 372215116Sdes } 373215116Sdes } 374215116Sdes 375215116Sdes switch (convert_format) { 376215116Sdes case FMT_RFC4716: 377215116Sdes do_convert_to_ssh2(pw, k); 378215116Sdes break; 379215116Sdes case FMT_PKCS8: 380215116Sdes do_convert_to_pkcs8(k); 381215116Sdes break; 382215116Sdes case FMT_PEM: 383215116Sdes do_convert_to_pem(k); 384215116Sdes break; 385215116Sdes default: 386215116Sdes fatal("%s: unknown key format %d", __func__, convert_format); 387215116Sdes } 388215116Sdes exit(0); 389215116Sdes} 390215116Sdes 391215116Sdesstatic void 39269587Sgreenbuffer_get_bignum_bits(Buffer *b, BIGNUM *value) 39369587Sgreen{ 394137015Sdes u_int bignum_bits = buffer_get_int(b); 395137015Sdes u_int bytes = (bignum_bits + 7) / 8; 39676259Sgreen 39769587Sgreen if (buffer_len(b) < bytes) 39876259Sgreen fatal("buffer_get_bignum_bits: input buffer too small: " 39976259Sgreen "need %d have %d", bytes, buffer_len(b)); 400164146Sdes if (BN_bin2bn(buffer_ptr(b), bytes, value) == NULL) 401164146Sdes fatal("buffer_get_bignum_bits: BN_bin2bn failed"); 40269587Sgreen buffer_consume(b, bytes); 40369587Sgreen} 40469587Sgreen 40592555Sdesstatic Key * 40692555Sdesdo_convert_private_ssh2_from_blob(u_char *blob, u_int blen) 40769587Sgreen{ 40869587Sgreen Buffer b; 40969587Sgreen Key *key = NULL; 41069587Sgreen char *type, *cipher; 41192555Sdes u_char *sig, data[] = "abcde12345"; 41292555Sdes int magic, rlen, ktype, i1, i2, i3, i4; 41392555Sdes u_int slen; 41492555Sdes u_long e; 41569587Sgreen 41669587Sgreen buffer_init(&b); 41769587Sgreen buffer_append(&b, blob, blen); 41869587Sgreen 419181111Sdes magic = buffer_get_int(&b); 42069587Sgreen if (magic != SSH_COM_PRIVATE_KEY_MAGIC) { 42169587Sgreen error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC); 42269587Sgreen buffer_free(&b); 42369587Sgreen return NULL; 42469587Sgreen } 42592555Sdes i1 = buffer_get_int(&b); 42669587Sgreen type = buffer_get_string(&b, NULL); 42769587Sgreen cipher = buffer_get_string(&b, NULL); 42892555Sdes i2 = buffer_get_int(&b); 42992555Sdes i3 = buffer_get_int(&b); 43092555Sdes i4 = buffer_get_int(&b); 431181111Sdes debug("ignore (%d %d %d %d)", i1, i2, i3, i4); 43269587Sgreen if (strcmp(cipher, "none") != 0) { 43369587Sgreen error("unsupported cipher %s", cipher); 434263970Sdes free(cipher); 43569587Sgreen buffer_free(&b); 436263970Sdes free(type); 43769587Sgreen return NULL; 43869587Sgreen } 439263970Sdes free(cipher); 44069587Sgreen 44176259Sgreen if (strstr(type, "dsa")) { 44276259Sgreen ktype = KEY_DSA; 44376259Sgreen } else if (strstr(type, "rsa")) { 44476259Sgreen ktype = KEY_RSA; 44576259Sgreen } else { 446146998Sdes buffer_free(&b); 447263970Sdes free(type); 44869587Sgreen return NULL; 44969587Sgreen } 45076259Sgreen key = key_new_private(ktype); 451263970Sdes free(type); 45276259Sgreen 45376259Sgreen switch (key->type) { 45476259Sgreen case KEY_DSA: 45576259Sgreen buffer_get_bignum_bits(&b, key->dsa->p); 45676259Sgreen buffer_get_bignum_bits(&b, key->dsa->g); 45776259Sgreen buffer_get_bignum_bits(&b, key->dsa->q); 45876259Sgreen buffer_get_bignum_bits(&b, key->dsa->pub_key); 45976259Sgreen buffer_get_bignum_bits(&b, key->dsa->priv_key); 46076259Sgreen break; 46176259Sgreen case KEY_RSA: 462181111Sdes e = buffer_get_char(&b); 46392555Sdes debug("e %lx", e); 46492555Sdes if (e < 30) { 46592555Sdes e <<= 8; 46692555Sdes e += buffer_get_char(&b); 46792555Sdes debug("e %lx", e); 46892555Sdes e <<= 8; 46992555Sdes e += buffer_get_char(&b); 47092555Sdes debug("e %lx", e); 47192555Sdes } 47292555Sdes if (!BN_set_word(key->rsa->e, e)) { 47376259Sgreen buffer_free(&b); 47476259Sgreen key_free(key); 47576259Sgreen return NULL; 47676259Sgreen } 47776259Sgreen buffer_get_bignum_bits(&b, key->rsa->d); 47876259Sgreen buffer_get_bignum_bits(&b, key->rsa->n); 47976259Sgreen buffer_get_bignum_bits(&b, key->rsa->iqmp); 48076259Sgreen buffer_get_bignum_bits(&b, key->rsa->q); 48176259Sgreen buffer_get_bignum_bits(&b, key->rsa->p); 48292555Sdes rsa_generate_additional_parameters(key->rsa); 48376259Sgreen break; 48476259Sgreen } 48569587Sgreen rlen = buffer_len(&b); 48692555Sdes if (rlen != 0) 48776259Sgreen error("do_convert_private_ssh2_from_blob: " 48876259Sgreen "remaining bytes in key blob %d", rlen); 48969587Sgreen buffer_free(&b); 49076259Sgreen 49192555Sdes /* try the key */ 49292555Sdes key_sign(key, &sig, &slen, data, sizeof(data)); 49392555Sdes key_verify(key, sig, slen, data, sizeof(data)); 494263970Sdes free(sig); 49569587Sgreen return key; 49669587Sgreen} 49769587Sgreen 498162852Sdesstatic int 499162852Sdesget_line(FILE *fp, char *line, size_t len) 500162852Sdes{ 501162852Sdes int c; 502162852Sdes size_t pos = 0; 503162852Sdes 504162852Sdes line[0] = '\0'; 505162852Sdes while ((c = fgetc(fp)) != EOF) { 506162852Sdes if (pos >= len - 1) { 507162852Sdes fprintf(stderr, "input line too long.\n"); 508162852Sdes exit(1); 509162852Sdes } 510162852Sdes switch (c) { 511162852Sdes case '\r': 512162852Sdes c = fgetc(fp); 513162852Sdes if (c != EOF && c != '\n' && ungetc(c, fp) == EOF) { 514162852Sdes fprintf(stderr, "unget: %s\n", strerror(errno)); 515162852Sdes exit(1); 516162852Sdes } 517162852Sdes return pos; 518162852Sdes case '\n': 519162852Sdes return pos; 520162852Sdes } 521162852Sdes line[pos++] = c; 522162852Sdes line[pos] = '\0'; 523162852Sdes } 524181111Sdes /* We reached EOF */ 525181111Sdes return -1; 526162852Sdes} 527162852Sdes 52892555Sdesstatic void 529215116Sdesdo_convert_from_ssh2(struct passwd *pw, Key **k, int *private) 53060573Skris{ 53160573Skris int blen; 53298675Sdes u_int len; 533162852Sdes char line[1024]; 53492555Sdes u_char blob[8096]; 53560573Skris char encoded[8096]; 536215116Sdes int escaped = 0; 53760573Skris FILE *fp; 53860573Skris 539215116Sdes if ((fp = fopen(identity_file, "r")) == NULL) 540215116Sdes fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); 54160573Skris encoded[0] = '\0'; 542162852Sdes while ((blen = get_line(fp, line, sizeof(line))) != -1) { 543263970Sdes if (blen > 0 && line[blen - 1] == '\\') 54460573Skris escaped++; 54560573Skris if (strncmp(line, "----", 4) == 0 || 54660573Skris strstr(line, ": ") != NULL) { 54769587Sgreen if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL) 548215116Sdes *private = 1; 54992555Sdes if (strstr(line, " END ") != NULL) { 55092555Sdes break; 55192555Sdes } 55276259Sgreen /* fprintf(stderr, "ignore: %s", line); */ 55360573Skris continue; 55460573Skris } 55560573Skris if (escaped) { 55660573Skris escaped--; 55776259Sgreen /* fprintf(stderr, "escaped: %s", line); */ 55860573Skris continue; 55960573Skris } 56060573Skris strlcat(encoded, line, sizeof(encoded)); 56160573Skris } 56298675Sdes len = strlen(encoded); 56398675Sdes if (((len % 4) == 3) && 56498675Sdes (encoded[len-1] == '=') && 56598675Sdes (encoded[len-2] == '=') && 56698675Sdes (encoded[len-3] == '=')) 56798675Sdes encoded[len-3] = '\0'; 56892555Sdes blen = uudecode(encoded, blob, sizeof(blob)); 56960573Skris if (blen < 0) { 57060573Skris fprintf(stderr, "uudecode failed.\n"); 57160573Skris exit(1); 57260573Skris } 573215116Sdes *k = *private ? 57469587Sgreen do_convert_private_ssh2_from_blob(blob, blen) : 57576259Sgreen key_from_blob(blob, blen); 576215116Sdes if (*k == NULL) { 57769587Sgreen fprintf(stderr, "decode blob failed.\n"); 57869587Sgreen exit(1); 57969587Sgreen } 580215116Sdes fclose(fp); 581215116Sdes} 582215116Sdes 583215116Sdesstatic void 584215116Sdesdo_convert_from_pkcs8(Key **k, int *private) 585215116Sdes{ 586215116Sdes EVP_PKEY *pubkey; 587215116Sdes FILE *fp; 588215116Sdes 589215116Sdes if ((fp = fopen(identity_file, "r")) == NULL) 590215116Sdes fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); 591215116Sdes if ((pubkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { 592215116Sdes fatal("%s: %s is not a recognised public key format", __func__, 593215116Sdes identity_file); 594215116Sdes } 595215116Sdes fclose(fp); 596215116Sdes switch (EVP_PKEY_type(pubkey->type)) { 597215116Sdes case EVP_PKEY_RSA: 598215116Sdes *k = key_new(KEY_UNSPEC); 599215116Sdes (*k)->type = KEY_RSA; 600215116Sdes (*k)->rsa = EVP_PKEY_get1_RSA(pubkey); 601215116Sdes break; 602215116Sdes case EVP_PKEY_DSA: 603215116Sdes *k = key_new(KEY_UNSPEC); 604215116Sdes (*k)->type = KEY_DSA; 605215116Sdes (*k)->dsa = EVP_PKEY_get1_DSA(pubkey); 606215116Sdes break; 607221420Sdes#ifdef OPENSSL_HAS_ECC 608221420Sdes case EVP_PKEY_EC: 609221420Sdes *k = key_new(KEY_UNSPEC); 610221420Sdes (*k)->type = KEY_ECDSA; 611221420Sdes (*k)->ecdsa = EVP_PKEY_get1_EC_KEY(pubkey); 612221420Sdes (*k)->ecdsa_nid = key_ecdsa_key_to_nid((*k)->ecdsa); 613221420Sdes break; 614221420Sdes#endif 615215116Sdes default: 616215116Sdes fatal("%s: unsupported pubkey type %d", __func__, 617215116Sdes EVP_PKEY_type(pubkey->type)); 618215116Sdes } 619215116Sdes EVP_PKEY_free(pubkey); 620215116Sdes return; 621215116Sdes} 622215116Sdes 623215116Sdesstatic void 624215116Sdesdo_convert_from_pem(Key **k, int *private) 625215116Sdes{ 626215116Sdes FILE *fp; 627215116Sdes RSA *rsa; 628215116Sdes#ifdef notyet 629215116Sdes DSA *dsa; 630215116Sdes#endif 631215116Sdes 632215116Sdes if ((fp = fopen(identity_file, "r")) == NULL) 633215116Sdes fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); 634215116Sdes if ((rsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL)) != NULL) { 635215116Sdes *k = key_new(KEY_UNSPEC); 636215116Sdes (*k)->type = KEY_RSA; 637215116Sdes (*k)->rsa = rsa; 638215116Sdes fclose(fp); 639215116Sdes return; 640215116Sdes } 641215116Sdes#if notyet /* OpenSSH 0.9.8 lacks this function */ 642215116Sdes rewind(fp); 643215116Sdes if ((dsa = PEM_read_DSAPublicKey(fp, NULL, NULL, NULL)) != NULL) { 644215116Sdes *k = key_new(KEY_UNSPEC); 645215116Sdes (*k)->type = KEY_DSA; 646215116Sdes (*k)->dsa = dsa; 647215116Sdes fclose(fp); 648215116Sdes return; 649215116Sdes } 650221420Sdes /* XXX ECDSA */ 651215116Sdes#endif 652215116Sdes fatal("%s: unrecognised raw private key format", __func__); 653215116Sdes} 654215116Sdes 655215116Sdesstatic void 656215116Sdesdo_convert_from(struct passwd *pw) 657215116Sdes{ 658215116Sdes Key *k = NULL; 659215116Sdes int private = 0, ok = 0; 660215116Sdes struct stat st; 661215116Sdes 662215116Sdes if (!have_identity) 663215116Sdes ask_filename(pw, "Enter file in which the key is"); 664215116Sdes if (stat(identity_file, &st) < 0) 665215116Sdes fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); 666215116Sdes 667215116Sdes switch (convert_format) { 668215116Sdes case FMT_RFC4716: 669215116Sdes do_convert_from_ssh2(pw, &k, &private); 670215116Sdes break; 671215116Sdes case FMT_PKCS8: 672215116Sdes do_convert_from_pkcs8(&k, &private); 673215116Sdes break; 674215116Sdes case FMT_PEM: 675215116Sdes do_convert_from_pem(&k, &private); 676215116Sdes break; 677215116Sdes default: 678215116Sdes fatal("%s: unknown key format %d", __func__, convert_format); 679215116Sdes } 680215116Sdes 681215116Sdes if (!private) 682215116Sdes ok = key_write(k, stdout); 683215116Sdes if (ok) 684215116Sdes fprintf(stdout, "\n"); 685215116Sdes else { 686215116Sdes switch (k->type) { 687215116Sdes case KEY_DSA: 688215116Sdes ok = PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, 689215116Sdes NULL, 0, NULL, NULL); 690215116Sdes break; 691221420Sdes#ifdef OPENSSL_HAS_ECC 692221420Sdes case KEY_ECDSA: 693221420Sdes ok = PEM_write_ECPrivateKey(stdout, k->ecdsa, NULL, 694221420Sdes NULL, 0, NULL, NULL); 695221420Sdes break; 696221420Sdes#endif 697215116Sdes case KEY_RSA: 698215116Sdes ok = PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, 699215116Sdes NULL, 0, NULL, NULL); 700215116Sdes break; 701215116Sdes default: 702215116Sdes fatal("%s: unsupported key type %s", __func__, 703215116Sdes key_type(k)); 704215116Sdes } 705215116Sdes } 706215116Sdes 70769587Sgreen if (!ok) { 708192595Sdes fprintf(stderr, "key write failed\n"); 70969587Sgreen exit(1); 71069587Sgreen } 71160573Skris key_free(k); 71260573Skris exit(0); 71360573Skris} 71460573Skris 71592555Sdesstatic void 71660573Skrisdo_print_public(struct passwd *pw) 71760573Skris{ 71876259Sgreen Key *prv; 71960573Skris struct stat st; 72060573Skris 72160573Skris if (!have_identity) 72260573Skris ask_filename(pw, "Enter file in which the key is"); 72360573Skris if (stat(identity_file, &st) < 0) { 72460573Skris perror(identity_file); 72560573Skris exit(1); 72660573Skris } 72792555Sdes prv = load_identity(identity_file); 72876259Sgreen if (prv == NULL) { 72960573Skris fprintf(stderr, "load failed\n"); 73060573Skris exit(1); 73160573Skris } 73276259Sgreen if (!key_write(prv, stdout)) 73360573Skris fprintf(stderr, "key_write failed"); 73476259Sgreen key_free(prv); 73560573Skris fprintf(stdout, "\n"); 73660573Skris exit(0); 73760573Skris} 73860573Skris 73992555Sdesstatic void 740215116Sdesdo_download(struct passwd *pw) 74192555Sdes{ 742204917Sdes#ifdef ENABLE_PKCS11 74398675Sdes Key **keys = NULL; 744204917Sdes int i, nkeys; 745251135Sdes enum fp_rep rep; 746251135Sdes enum fp_type fptype; 747251135Sdes char *fp, *ra; 74892555Sdes 749251135Sdes fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; 750251135Sdes rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; 751251135Sdes 752204917Sdes pkcs11_init(0); 753204917Sdes nkeys = pkcs11_add_provider(pkcs11provider, NULL, &keys); 754204917Sdes if (nkeys <= 0) 755204917Sdes fatal("cannot read public key from pkcs11"); 756204917Sdes for (i = 0; i < nkeys; i++) { 757251135Sdes if (print_fingerprint) { 758251135Sdes fp = key_fingerprint(keys[i], fptype, rep); 759251135Sdes ra = key_fingerprint(keys[i], SSH_FP_MD5, 760251135Sdes SSH_FP_RANDOMART); 761251135Sdes printf("%u %s %s (PKCS11 key)\n", key_size(keys[i]), 762251135Sdes fp, key_type(keys[i])); 763251135Sdes if (log_level >= SYSLOG_LEVEL_VERBOSE) 764251135Sdes printf("%s\n", ra); 765263970Sdes free(ra); 766263970Sdes free(fp); 767251135Sdes } else { 768251135Sdes key_write(keys[i], stdout); 769251135Sdes fprintf(stdout, "\n"); 770251135Sdes } 77198675Sdes key_free(keys[i]); 77298675Sdes } 773263970Sdes free(keys); 774204917Sdes pkcs11_terminate(); 77592555Sdes exit(0); 776204917Sdes#else 777204917Sdes fatal("no pkcs11 support"); 778204917Sdes#endif /* ENABLE_PKCS11 */ 77992555Sdes} 78092555Sdes 78192555Sdesstatic void 78257429Smarkmdo_fingerprint(struct passwd *pw) 78357429Smarkm{ 78457429Smarkm FILE *f; 78560573Skris Key *public; 786181111Sdes char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra; 787181111Sdes int i, skip = 0, num = 0, invalid = 1; 78892555Sdes enum fp_rep rep; 78992555Sdes enum fp_type fptype; 79057429Smarkm struct stat st; 79157429Smarkm 79276259Sgreen fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; 79376259Sgreen rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; 79476259Sgreen 79557429Smarkm if (!have_identity) 79657429Smarkm ask_filename(pw, "Enter file in which the key is"); 79757429Smarkm if (stat(identity_file, &st) < 0) { 79857429Smarkm perror(identity_file); 79957429Smarkm exit(1); 80057429Smarkm } 80176259Sgreen public = key_load_public(identity_file, &comment); 80276259Sgreen if (public != NULL) { 80376259Sgreen fp = key_fingerprint(public, fptype, rep); 804204917Sdes ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); 805181111Sdes printf("%u %s %s (%s)\n", key_size(public), fp, comment, 806181111Sdes key_type(public)); 807181111Sdes if (log_level >= SYSLOG_LEVEL_VERBOSE) 808181111Sdes printf("%s\n", ra); 80960573Skris key_free(public); 810263970Sdes free(comment); 811263970Sdes free(ra); 812263970Sdes free(fp); 81357429Smarkm exit(0); 81457429Smarkm } 815162852Sdes if (comment) { 816263970Sdes free(comment); 817162852Sdes comment = NULL; 818162852Sdes } 81957429Smarkm 820215116Sdes if ((f = fopen(identity_file, "r")) == NULL) 821215116Sdes fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); 822215116Sdes 823215116Sdes while (fgets(line, sizeof(line), f)) { 824215116Sdes if ((cp = strchr(line, '\n')) == NULL) { 825215116Sdes error("line %d too long: %.40s...", 826215116Sdes num + 1, line); 827215116Sdes skip = 1; 828215116Sdes continue; 829215116Sdes } 830215116Sdes num++; 831215116Sdes if (skip) { 832215116Sdes skip = 0; 833215116Sdes continue; 834215116Sdes } 835215116Sdes *cp = '\0'; 836215116Sdes 837215116Sdes /* Skip leading whitespace, empty and comment lines. */ 838215116Sdes for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 839215116Sdes ; 840215116Sdes if (!*cp || *cp == '\n' || *cp == '#') 841215116Sdes continue; 842215116Sdes i = strtol(cp, &ep, 10); 843215116Sdes if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) { 844215116Sdes int quoted = 0; 845215116Sdes comment = cp; 846215116Sdes for (; *cp && (quoted || (*cp != ' ' && 847215116Sdes *cp != '\t')); cp++) { 848215116Sdes if (*cp == '\\' && cp[1] == '"') 849215116Sdes cp++; /* Skip both */ 850215116Sdes else if (*cp == '"') 851215116Sdes quoted = !quoted; 85257429Smarkm } 853215116Sdes if (!*cp) 85457429Smarkm continue; 855215116Sdes *cp++ = '\0'; 856215116Sdes } 857215116Sdes ep = cp; 858215116Sdes public = key_new(KEY_RSA1); 859215116Sdes if (key_read(public, &cp) != 1) { 860215116Sdes cp = ep; 861215116Sdes key_free(public); 862215116Sdes public = key_new(KEY_UNSPEC); 86376259Sgreen if (key_read(public, &cp) != 1) { 86476259Sgreen key_free(public); 865215116Sdes continue; 86657429Smarkm } 86757429Smarkm } 868215116Sdes comment = *cp ? cp : comment; 869215116Sdes fp = key_fingerprint(public, fptype, rep); 870215116Sdes ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); 871215116Sdes printf("%u %s %s (%s)\n", key_size(public), fp, 872215116Sdes comment ? comment : "no comment", key_type(public)); 873215116Sdes if (log_level >= SYSLOG_LEVEL_VERBOSE) 874215116Sdes printf("%s\n", ra); 875263970Sdes free(ra); 876263970Sdes free(fp); 877215116Sdes key_free(public); 878215116Sdes invalid = 0; 87957429Smarkm } 880215116Sdes fclose(f); 881215116Sdes 88257429Smarkm if (invalid) { 88392555Sdes printf("%s is not a public key file.\n", identity_file); 88457429Smarkm exit(1); 88557429Smarkm } 88657429Smarkm exit(0); 88757429Smarkm} 88857429Smarkm 889146998Sdesstatic void 890247485Sdesdo_gen_all_hostkeys(struct passwd *pw) 891247485Sdes{ 892247485Sdes struct { 893247485Sdes char *key_type; 894247485Sdes char *key_type_display; 895247485Sdes char *path; 896247485Sdes } key_types[] = { 897247485Sdes { "rsa1", "RSA1", _PATH_HOST_KEY_FILE }, 898247485Sdes { "rsa", "RSA" ,_PATH_HOST_RSA_KEY_FILE }, 899247485Sdes { "dsa", "DSA", _PATH_HOST_DSA_KEY_FILE }, 900247485Sdes#ifdef OPENSSL_HAS_ECC 901247485Sdes { "ecdsa", "ECDSA",_PATH_HOST_ECDSA_KEY_FILE }, 902247485Sdes#endif 903263970Sdes { "ed25519", "ED25519",_PATH_HOST_ED25519_KEY_FILE }, 904247485Sdes { NULL, NULL, NULL } 905247485Sdes }; 906247485Sdes 907247485Sdes int first = 0; 908247485Sdes struct stat st; 909247485Sdes Key *private, *public; 910247485Sdes char comment[1024]; 911247485Sdes int i, type, fd; 912247485Sdes FILE *f; 913247485Sdes 914247485Sdes for (i = 0; key_types[i].key_type; i++) { 915247485Sdes if (stat(key_types[i].path, &st) == 0) 916247485Sdes continue; 917247485Sdes if (errno != ENOENT) { 918247485Sdes printf("Could not stat %s: %s", key_types[i].path, 919247485Sdes strerror(errno)); 920247485Sdes first = 0; 921247485Sdes continue; 922247485Sdes } 923247485Sdes 924247485Sdes if (first == 0) { 925247485Sdes first = 1; 926247485Sdes printf("%s: generating new host keys: ", __progname); 927247485Sdes } 928247485Sdes printf("%s ", key_types[i].key_type_display); 929247485Sdes fflush(stdout); 930247485Sdes type = key_type_from_name(key_types[i].key_type); 931247485Sdes strlcpy(identity_file, key_types[i].path, sizeof(identity_file)); 932247485Sdes bits = 0; 933247485Sdes type_bits_valid(type, &bits); 934247485Sdes private = key_generate(type, bits); 935247485Sdes if (private == NULL) { 936247485Sdes fprintf(stderr, "key_generate failed\n"); 937247485Sdes first = 0; 938247485Sdes continue; 939247485Sdes } 940247485Sdes public = key_from_private(private); 941247485Sdes snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, 942247485Sdes hostname); 943263970Sdes if (!key_save_private(private, identity_file, "", comment, 944263970Sdes use_new_format, new_format_cipher, rounds)) { 945247485Sdes printf("Saving the key failed: %s.\n", identity_file); 946247485Sdes key_free(private); 947247485Sdes key_free(public); 948247485Sdes first = 0; 949247485Sdes continue; 950247485Sdes } 951247485Sdes key_free(private); 952247485Sdes strlcat(identity_file, ".pub", sizeof(identity_file)); 953247485Sdes fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); 954247485Sdes if (fd == -1) { 955247485Sdes printf("Could not save your public key in %s\n", 956247485Sdes identity_file); 957247485Sdes key_free(public); 958247485Sdes first = 0; 959247485Sdes continue; 960247485Sdes } 961247485Sdes f = fdopen(fd, "w"); 962247485Sdes if (f == NULL) { 963247485Sdes printf("fdopen %s failed\n", identity_file); 964247485Sdes key_free(public); 965247485Sdes first = 0; 966247485Sdes continue; 967247485Sdes } 968247485Sdes if (!key_write(public, f)) { 969247485Sdes fprintf(stderr, "write key failed\n"); 970247485Sdes key_free(public); 971247485Sdes first = 0; 972247485Sdes continue; 973247485Sdes } 974247485Sdes fprintf(f, " %s\n", comment); 975247485Sdes fclose(f); 976247485Sdes key_free(public); 977247485Sdes 978247485Sdes } 979247485Sdes if (first != 0) 980247485Sdes printf("\n"); 981247485Sdes} 982247485Sdes 983247485Sdesstatic void 984204917Sdesprinthost(FILE *f, const char *name, Key *public, int ca, int hash) 985146998Sdes{ 986181111Sdes if (print_fingerprint) { 987181111Sdes enum fp_rep rep; 988181111Sdes enum fp_type fptype; 989181111Sdes char *fp, *ra; 990181111Sdes 991181111Sdes fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; 992181111Sdes rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; 993181111Sdes fp = key_fingerprint(public, fptype, rep); 994204917Sdes ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); 995181111Sdes printf("%u %s %s (%s)\n", key_size(public), fp, name, 996181111Sdes key_type(public)); 997181111Sdes if (log_level >= SYSLOG_LEVEL_VERBOSE) 998181111Sdes printf("%s\n", ra); 999263970Sdes free(ra); 1000263970Sdes free(fp); 1001181111Sdes } else { 1002181111Sdes if (hash && (name = host_hash(name, NULL, 0)) == NULL) 1003181111Sdes fatal("hash_host failed"); 1004204917Sdes fprintf(f, "%s%s%s ", ca ? CA_MARKER : "", ca ? " " : "", name); 1005181111Sdes if (!key_write(public, f)) 1006181111Sdes fatal("key_write failed"); 1007181111Sdes fprintf(f, "\n"); 1008181111Sdes } 1009146998Sdes} 1010146998Sdes 1011146998Sdesstatic void 1012146998Sdesdo_known_hosts(struct passwd *pw, const char *name) 1013146998Sdes{ 1014146998Sdes FILE *in, *out = stdout; 1015204917Sdes Key *pub; 1016146998Sdes char *cp, *cp2, *kp, *kp2; 1017146998Sdes char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN]; 1018181111Sdes int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0; 1019204917Sdes int ca; 1020263970Sdes int found_key = 0; 1021146998Sdes 1022146998Sdes if (!have_identity) { 1023146998Sdes cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid); 1024146998Sdes if (strlcpy(identity_file, cp, sizeof(identity_file)) >= 1025146998Sdes sizeof(identity_file)) 1026146998Sdes fatal("Specified known hosts path too long"); 1027263970Sdes free(cp); 1028146998Sdes have_identity = 1; 1029146998Sdes } 1030146998Sdes if ((in = fopen(identity_file, "r")) == NULL) 1031215116Sdes fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); 1032146998Sdes 1033146998Sdes /* 1034146998Sdes * Find hosts goes to stdout, hash and deletions happen in-place 1035146998Sdes * A corner case is ssh-keygen -HF foo, which should go to stdout 1036146998Sdes */ 1037146998Sdes if (!find_host && (hash_hosts || delete_host)) { 1038146998Sdes if (strlcpy(tmp, identity_file, sizeof(tmp)) >= sizeof(tmp) || 1039146998Sdes strlcat(tmp, ".XXXXXXXXXX", sizeof(tmp)) >= sizeof(tmp) || 1040146998Sdes strlcpy(old, identity_file, sizeof(old)) >= sizeof(old) || 1041146998Sdes strlcat(old, ".old", sizeof(old)) >= sizeof(old)) 1042146998Sdes fatal("known_hosts path too long"); 1043146998Sdes umask(077); 1044146998Sdes if ((c = mkstemp(tmp)) == -1) 1045146998Sdes fatal("mkstemp: %s", strerror(errno)); 1046146998Sdes if ((out = fdopen(c, "w")) == NULL) { 1047146998Sdes c = errno; 1048146998Sdes unlink(tmp); 1049146998Sdes fatal("fdopen: %s", strerror(c)); 1050146998Sdes } 1051146998Sdes inplace = 1; 1052146998Sdes } 1053146998Sdes 1054146998Sdes while (fgets(line, sizeof(line), in)) { 1055181111Sdes if ((cp = strchr(line, '\n')) == NULL) { 1056181111Sdes error("line %d too long: %.40s...", num + 1, line); 1057146998Sdes skip = 1; 1058146998Sdes invalid = 1; 1059146998Sdes continue; 1060146998Sdes } 1061181111Sdes num++; 1062146998Sdes if (skip) { 1063146998Sdes skip = 0; 1064146998Sdes continue; 1065146998Sdes } 1066181111Sdes *cp = '\0'; 1067146998Sdes 1068146998Sdes /* Skip leading whitespace, empty and comment lines. */ 1069146998Sdes for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 1070146998Sdes ; 1071146998Sdes if (!*cp || *cp == '\n' || *cp == '#') { 1072146998Sdes if (inplace) 1073146998Sdes fprintf(out, "%s\n", cp); 1074146998Sdes continue; 1075146998Sdes } 1076204917Sdes /* Check whether this is a CA key */ 1077204917Sdes if (strncasecmp(cp, CA_MARKER, sizeof(CA_MARKER) - 1) == 0 && 1078204917Sdes (cp[sizeof(CA_MARKER) - 1] == ' ' || 1079204917Sdes cp[sizeof(CA_MARKER) - 1] == '\t')) { 1080204917Sdes ca = 1; 1081204917Sdes cp += sizeof(CA_MARKER); 1082204917Sdes } else 1083204917Sdes ca = 0; 1084204917Sdes 1085146998Sdes /* Find the end of the host name portion. */ 1086146998Sdes for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++) 1087146998Sdes ; 1088204917Sdes 1089146998Sdes if (*kp == '\0' || *(kp + 1) == '\0') { 1090146998Sdes error("line %d missing key: %.40s...", 1091146998Sdes num, line); 1092146998Sdes invalid = 1; 1093146998Sdes continue; 1094146998Sdes } 1095146998Sdes *kp++ = '\0'; 1096146998Sdes kp2 = kp; 1097146998Sdes 1098204917Sdes pub = key_new(KEY_RSA1); 1099204917Sdes if (key_read(pub, &kp) != 1) { 1100146998Sdes kp = kp2; 1101204917Sdes key_free(pub); 1102204917Sdes pub = key_new(KEY_UNSPEC); 1103204917Sdes if (key_read(pub, &kp) != 1) { 1104146998Sdes error("line %d invalid key: %.40s...", 1105146998Sdes num, line); 1106204917Sdes key_free(pub); 1107146998Sdes invalid = 1; 1108146998Sdes continue; 1109146998Sdes } 1110146998Sdes } 1111146998Sdes 1112146998Sdes if (*cp == HASH_DELIM) { 1113146998Sdes if (find_host || delete_host) { 1114146998Sdes cp2 = host_hash(name, cp, strlen(cp)); 1115146998Sdes if (cp2 == NULL) { 1116146998Sdes error("line %d: invalid hashed " 1117146998Sdes "name: %.64s...", num, line); 1118146998Sdes invalid = 1; 1119146998Sdes continue; 1120146998Sdes } 1121146998Sdes c = (strcmp(cp2, cp) == 0); 1122146998Sdes if (find_host && c) { 1123263970Sdes if (!quiet) 1124263970Sdes printf("# Host %s found: " 1125263970Sdes "line %d type %s%s\n", name, 1126263970Sdes num, key_type(pub), 1127263970Sdes ca ? " (CA key)" : ""); 1128204917Sdes printhost(out, cp, pub, ca, 0); 1129263970Sdes found_key = 1; 1130146998Sdes } 1131251135Sdes if (delete_host) { 1132251135Sdes if (!c && !ca) 1133251135Sdes printhost(out, cp, pub, ca, 0); 1134251135Sdes else 1135251135Sdes printf("# Host %s found: " 1136251135Sdes "line %d type %s\n", name, 1137251135Sdes num, key_type(pub)); 1138251135Sdes } 1139146998Sdes } else if (hash_hosts) 1140204917Sdes printhost(out, cp, pub, ca, 0); 1141146998Sdes } else { 1142146998Sdes if (find_host || delete_host) { 1143146998Sdes c = (match_hostname(name, cp, 1144146998Sdes strlen(cp)) == 1); 1145146998Sdes if (find_host && c) { 1146263970Sdes if (!quiet) 1147263970Sdes printf("# Host %s found: " 1148263970Sdes "line %d type %s%s\n", name, 1149263970Sdes num, key_type(pub), 1150263970Sdes ca ? " (CA key)" : ""); 1151204917Sdes printhost(out, name, pub, 1152204917Sdes ca, hash_hosts && !ca); 1153263970Sdes found_key = 1; 1154146998Sdes } 1155251135Sdes if (delete_host) { 1156251135Sdes if (!c && !ca) 1157251135Sdes printhost(out, cp, pub, ca, 0); 1158251135Sdes else 1159251135Sdes printf("# Host %s found: " 1160251135Sdes "line %d type %s\n", name, 1161251135Sdes num, key_type(pub)); 1162251135Sdes } 1163146998Sdes } else if (hash_hosts) { 1164147001Sdes for (cp2 = strsep(&cp, ","); 1165146998Sdes cp2 != NULL && *cp2 != '\0'; 1166146998Sdes cp2 = strsep(&cp, ",")) { 1167204917Sdes if (ca) { 1168146998Sdes fprintf(stderr, "Warning: " 1169204917Sdes "ignoring CA key for host: " 1170204917Sdes "%.64s\n", cp2); 1171204917Sdes printhost(out, cp2, pub, ca, 0); 1172204917Sdes } else if (strcspn(cp2, "*?!") != 1173204917Sdes strlen(cp2)) { 1174204917Sdes fprintf(stderr, "Warning: " 1175146998Sdes "ignoring host name with " 1176146998Sdes "metacharacters: %.64s\n", 1177146998Sdes cp2); 1178204917Sdes printhost(out, cp2, pub, ca, 0); 1179204917Sdes } else 1180204917Sdes printhost(out, cp2, pub, ca, 1); 1181146998Sdes } 1182146998Sdes has_unhashed = 1; 1183146998Sdes } 1184146998Sdes } 1185204917Sdes key_free(pub); 1186146998Sdes } 1187146998Sdes fclose(in); 1188146998Sdes 1189146998Sdes if (invalid) { 1190181111Sdes fprintf(stderr, "%s is not a valid known_hosts file.\n", 1191146998Sdes identity_file); 1192146998Sdes if (inplace) { 1193146998Sdes fprintf(stderr, "Not replacing existing known_hosts " 1194147001Sdes "file because of errors\n"); 1195146998Sdes fclose(out); 1196146998Sdes unlink(tmp); 1197146998Sdes } 1198146998Sdes exit(1); 1199146998Sdes } 1200146998Sdes 1201146998Sdes if (inplace) { 1202146998Sdes fclose(out); 1203146998Sdes 1204146998Sdes /* Backup existing file */ 1205146998Sdes if (unlink(old) == -1 && errno != ENOENT) 1206146998Sdes fatal("unlink %.100s: %s", old, strerror(errno)); 1207146998Sdes if (link(identity_file, old) == -1) 1208146998Sdes fatal("link %.100s to %.100s: %s", identity_file, old, 1209146998Sdes strerror(errno)); 1210146998Sdes /* Move new one into place */ 1211146998Sdes if (rename(tmp, identity_file) == -1) { 1212146998Sdes error("rename\"%s\" to \"%s\": %s", tmp, identity_file, 1213146998Sdes strerror(errno)); 1214146998Sdes unlink(tmp); 1215146998Sdes unlink(old); 1216146998Sdes exit(1); 1217146998Sdes } 1218146998Sdes 1219146998Sdes fprintf(stderr, "%s updated.\n", identity_file); 1220146998Sdes fprintf(stderr, "Original contents retained as %s\n", old); 1221146998Sdes if (has_unhashed) { 1222146998Sdes fprintf(stderr, "WARNING: %s contains unhashed " 1223146998Sdes "entries\n", old); 1224146998Sdes fprintf(stderr, "Delete this file to ensure privacy " 1225149749Sdes "of hostnames\n"); 1226146998Sdes } 1227146998Sdes } 1228146998Sdes 1229263970Sdes exit (find_host && !found_key); 1230146998Sdes} 1231146998Sdes 123257429Smarkm/* 123357429Smarkm * Perform changing a passphrase. The argument is the passwd structure 123457429Smarkm * for the current user. 123557429Smarkm */ 123692555Sdesstatic void 123757429Smarkmdo_change_passphrase(struct passwd *pw) 123857429Smarkm{ 123957429Smarkm char *comment; 124057429Smarkm char *old_passphrase, *passphrase1, *passphrase2; 124157429Smarkm struct stat st; 124260573Skris Key *private; 124357429Smarkm 124457429Smarkm if (!have_identity) 124557429Smarkm ask_filename(pw, "Enter file in which the key is"); 124657429Smarkm if (stat(identity_file, &st) < 0) { 124757429Smarkm perror(identity_file); 124857429Smarkm exit(1); 124957429Smarkm } 125057429Smarkm /* Try to load the file with empty passphrase. */ 125176259Sgreen private = key_load_private(identity_file, "", &comment); 125276259Sgreen if (private == NULL) { 125357429Smarkm if (identity_passphrase) 125457429Smarkm old_passphrase = xstrdup(identity_passphrase); 125557429Smarkm else 125692555Sdes old_passphrase = 125792555Sdes read_passphrase("Enter old passphrase: ", 125892555Sdes RP_ALLOW_STDIN); 125992555Sdes private = key_load_private(identity_file, old_passphrase, 126092555Sdes &comment); 1261263970Sdes explicit_bzero(old_passphrase, strlen(old_passphrase)); 1262263970Sdes free(old_passphrase); 126376259Sgreen if (private == NULL) { 126457429Smarkm printf("Bad passphrase.\n"); 126557429Smarkm exit(1); 126657429Smarkm } 126757429Smarkm } 126857429Smarkm printf("Key has comment '%s'\n", comment); 126957429Smarkm 127057429Smarkm /* Ask the new passphrase (twice). */ 127157429Smarkm if (identity_new_passphrase) { 127257429Smarkm passphrase1 = xstrdup(identity_new_passphrase); 127357429Smarkm passphrase2 = NULL; 127457429Smarkm } else { 127557429Smarkm passphrase1 = 127692555Sdes read_passphrase("Enter new passphrase (empty for no " 127792555Sdes "passphrase): ", RP_ALLOW_STDIN); 127892555Sdes passphrase2 = read_passphrase("Enter same passphrase again: ", 127992555Sdes RP_ALLOW_STDIN); 128057429Smarkm 128157429Smarkm /* Verify that they are the same. */ 128257429Smarkm if (strcmp(passphrase1, passphrase2) != 0) { 1283263970Sdes explicit_bzero(passphrase1, strlen(passphrase1)); 1284263970Sdes explicit_bzero(passphrase2, strlen(passphrase2)); 1285263970Sdes free(passphrase1); 1286263970Sdes free(passphrase2); 128757429Smarkm printf("Pass phrases do not match. Try again.\n"); 128857429Smarkm exit(1); 128957429Smarkm } 129057429Smarkm /* Destroy the other copy. */ 1291263970Sdes explicit_bzero(passphrase2, strlen(passphrase2)); 1292263970Sdes free(passphrase2); 129357429Smarkm } 129457429Smarkm 129557429Smarkm /* Save the file using the new passphrase. */ 1296263970Sdes if (!key_save_private(private, identity_file, passphrase1, comment, 1297263970Sdes use_new_format, new_format_cipher, rounds)) { 129876259Sgreen printf("Saving the key failed: %s.\n", identity_file); 1299263970Sdes explicit_bzero(passphrase1, strlen(passphrase1)); 1300263970Sdes free(passphrase1); 130160573Skris key_free(private); 1302263970Sdes free(comment); 130357429Smarkm exit(1); 130457429Smarkm } 130557429Smarkm /* Destroy the passphrase and the copy of the key in memory. */ 1306263970Sdes explicit_bzero(passphrase1, strlen(passphrase1)); 1307263970Sdes free(passphrase1); 130860573Skris key_free(private); /* Destroys contents */ 1309263970Sdes free(comment); 131057429Smarkm 131157429Smarkm printf("Your identification has been saved with the new passphrase.\n"); 131257429Smarkm exit(0); 131357429Smarkm} 131457429Smarkm 131557429Smarkm/* 1316124208Sdes * Print the SSHFP RR. 1317124208Sdes */ 1318162852Sdesstatic int 1319162852Sdesdo_print_resource_record(struct passwd *pw, char *fname, char *hname) 1320124208Sdes{ 1321124208Sdes Key *public; 1322124208Sdes char *comment = NULL; 1323124208Sdes struct stat st; 1324124208Sdes 1325162852Sdes if (fname == NULL) 1326263970Sdes fatal("%s: no filename", __func__); 1327162852Sdes if (stat(fname, &st) < 0) { 1328162852Sdes if (errno == ENOENT) 1329162852Sdes return 0; 1330162852Sdes perror(fname); 1331124208Sdes exit(1); 1332124208Sdes } 1333162852Sdes public = key_load_public(fname, &comment); 1334124208Sdes if (public != NULL) { 1335137015Sdes export_dns_rr(hname, public, stdout, print_generic); 1336124208Sdes key_free(public); 1337263970Sdes free(comment); 1338162852Sdes return 1; 1339124208Sdes } 1340124208Sdes if (comment) 1341263970Sdes free(comment); 1342124208Sdes 1343162852Sdes printf("failed to read v2 public key from %s.\n", fname); 1344124208Sdes exit(1); 1345124208Sdes} 1346124208Sdes 1347124208Sdes/* 134857429Smarkm * Change the comment of a private key file. 134957429Smarkm */ 135092555Sdesstatic void 135157429Smarkmdo_change_comment(struct passwd *pw) 135257429Smarkm{ 135376259Sgreen char new_comment[1024], *comment, *passphrase; 135460573Skris Key *private; 135560573Skris Key *public; 135657429Smarkm struct stat st; 135757429Smarkm FILE *f; 135876259Sgreen int fd; 135957429Smarkm 136057429Smarkm if (!have_identity) 136157429Smarkm ask_filename(pw, "Enter file in which the key is"); 136257429Smarkm if (stat(identity_file, &st) < 0) { 136357429Smarkm perror(identity_file); 136457429Smarkm exit(1); 136557429Smarkm } 136676259Sgreen private = key_load_private(identity_file, "", &comment); 136776259Sgreen if (private == NULL) { 136857429Smarkm if (identity_passphrase) 136957429Smarkm passphrase = xstrdup(identity_passphrase); 137057429Smarkm else if (identity_new_passphrase) 137157429Smarkm passphrase = xstrdup(identity_new_passphrase); 137257429Smarkm else 137392555Sdes passphrase = read_passphrase("Enter passphrase: ", 137492555Sdes RP_ALLOW_STDIN); 137557429Smarkm /* Try to load using the passphrase. */ 137676259Sgreen private = key_load_private(identity_file, passphrase, &comment); 137776259Sgreen if (private == NULL) { 1378263970Sdes explicit_bzero(passphrase, strlen(passphrase)); 1379263970Sdes free(passphrase); 138057429Smarkm printf("Bad passphrase.\n"); 138157429Smarkm exit(1); 138257429Smarkm } 138376259Sgreen } else { 138476259Sgreen passphrase = xstrdup(""); 138557429Smarkm } 138676259Sgreen if (private->type != KEY_RSA1) { 138776259Sgreen fprintf(stderr, "Comments are only supported for RSA1 keys.\n"); 138876259Sgreen key_free(private); 138976259Sgreen exit(1); 139092555Sdes } 139157429Smarkm printf("Key now has comment '%s'\n", comment); 139257429Smarkm 139357429Smarkm if (identity_comment) { 139457429Smarkm strlcpy(new_comment, identity_comment, sizeof(new_comment)); 139557429Smarkm } else { 139657429Smarkm printf("Enter new comment: "); 139757429Smarkm fflush(stdout); 139857429Smarkm if (!fgets(new_comment, sizeof(new_comment), stdin)) { 1399263970Sdes explicit_bzero(passphrase, strlen(passphrase)); 140060573Skris key_free(private); 140157429Smarkm exit(1); 140257429Smarkm } 1403181111Sdes new_comment[strcspn(new_comment, "\n")] = '\0'; 140457429Smarkm } 140557429Smarkm 140657429Smarkm /* Save the file using the new passphrase. */ 1407263970Sdes if (!key_save_private(private, identity_file, passphrase, new_comment, 1408263970Sdes use_new_format, new_format_cipher, rounds)) { 140976259Sgreen printf("Saving the key failed: %s.\n", identity_file); 1410263970Sdes explicit_bzero(passphrase, strlen(passphrase)); 1411263970Sdes free(passphrase); 141260573Skris key_free(private); 1413263970Sdes free(comment); 141457429Smarkm exit(1); 141557429Smarkm } 1416263970Sdes explicit_bzero(passphrase, strlen(passphrase)); 1417263970Sdes free(passphrase); 141876259Sgreen public = key_from_private(private); 141960573Skris key_free(private); 142057429Smarkm 142157429Smarkm strlcat(identity_file, ".pub", sizeof(identity_file)); 142276259Sgreen fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); 142376259Sgreen if (fd == -1) { 142457429Smarkm printf("Could not save your public key in %s\n", identity_file); 142557429Smarkm exit(1); 142657429Smarkm } 142776259Sgreen f = fdopen(fd, "w"); 142876259Sgreen if (f == NULL) { 1429192595Sdes printf("fdopen %s failed\n", identity_file); 143076259Sgreen exit(1); 143176259Sgreen } 143260573Skris if (!key_write(public, f)) 1433192595Sdes fprintf(stderr, "write key failed\n"); 143460573Skris key_free(public); 143560573Skris fprintf(f, " %s\n", new_comment); 143657429Smarkm fclose(f); 143757429Smarkm 1438263970Sdes free(comment); 143957429Smarkm 144057429Smarkm printf("The comment in your key file has been changed.\n"); 144157429Smarkm exit(0); 144257429Smarkm} 144357429Smarkm 1444204917Sdesstatic const char * 1445204917Sdesfmt_validity(u_int64_t valid_from, u_int64_t valid_to) 1446204917Sdes{ 1447204917Sdes char from[32], to[32]; 1448204917Sdes static char ret[64]; 1449204917Sdes time_t tt; 1450204917Sdes struct tm *tm; 1451204917Sdes 1452204917Sdes *from = *to = '\0'; 1453204917Sdes if (valid_from == 0 && valid_to == 0xffffffffffffffffULL) 1454204917Sdes return "forever"; 1455204917Sdes 1456204917Sdes if (valid_from != 0) { 1457204917Sdes /* XXX revisit INT_MAX in 2038 :) */ 1458204917Sdes tt = valid_from > INT_MAX ? INT_MAX : valid_from; 1459204917Sdes tm = localtime(&tt); 1460204917Sdes strftime(from, sizeof(from), "%Y-%m-%dT%H:%M:%S", tm); 1461204917Sdes } 1462204917Sdes if (valid_to != 0xffffffffffffffffULL) { 1463204917Sdes /* XXX revisit INT_MAX in 2038 :) */ 1464204917Sdes tt = valid_to > INT_MAX ? INT_MAX : valid_to; 1465204917Sdes tm = localtime(&tt); 1466204917Sdes strftime(to, sizeof(to), "%Y-%m-%dT%H:%M:%S", tm); 1467204917Sdes } 1468204917Sdes 1469204917Sdes if (valid_from == 0) { 1470204917Sdes snprintf(ret, sizeof(ret), "before %s", to); 1471204917Sdes return ret; 1472204917Sdes } 1473204917Sdes if (valid_to == 0xffffffffffffffffULL) { 1474204917Sdes snprintf(ret, sizeof(ret), "after %s", from); 1475204917Sdes return ret; 1476204917Sdes } 1477204917Sdes 1478204917Sdes snprintf(ret, sizeof(ret), "from %s to %s", from, to); 1479204917Sdes return ret; 1480204917Sdes} 1481204917Sdes 148292555Sdesstatic void 1483215116Sdesadd_flag_option(Buffer *c, const char *name) 1484204917Sdes{ 1485204917Sdes debug3("%s: %s", __func__, name); 1486204917Sdes buffer_put_cstring(c, name); 1487204917Sdes buffer_put_string(c, NULL, 0); 1488204917Sdes} 1489204917Sdes 1490204917Sdesstatic void 1491215116Sdesadd_string_option(Buffer *c, const char *name, const char *value) 1492204917Sdes{ 1493204917Sdes Buffer b; 1494204917Sdes 1495204917Sdes debug3("%s: %s=%s", __func__, name, value); 1496204917Sdes buffer_init(&b); 1497204917Sdes buffer_put_cstring(&b, value); 1498204917Sdes 1499204917Sdes buffer_put_cstring(c, name); 1500204917Sdes buffer_put_string(c, buffer_ptr(&b), buffer_len(&b)); 1501204917Sdes 1502204917Sdes buffer_free(&b); 1503204917Sdes} 1504204917Sdes 1505215116Sdes#define OPTIONS_CRITICAL 1 1506215116Sdes#define OPTIONS_EXTENSIONS 2 1507204917Sdesstatic void 1508215116Sdesprepare_options_buf(Buffer *c, int which) 1509204917Sdes{ 1510204917Sdes buffer_clear(c); 1511215116Sdes if ((which & OPTIONS_CRITICAL) != 0 && 1512215116Sdes certflags_command != NULL) 1513215116Sdes add_string_option(c, "force-command", certflags_command); 1514215116Sdes if ((which & OPTIONS_EXTENSIONS) != 0 && 1515247485Sdes (certflags_flags & CERTOPT_X_FWD) != 0) 1516247485Sdes add_flag_option(c, "permit-X11-forwarding"); 1517247485Sdes if ((which & OPTIONS_EXTENSIONS) != 0 && 1518215116Sdes (certflags_flags & CERTOPT_AGENT_FWD) != 0) 1519215116Sdes add_flag_option(c, "permit-agent-forwarding"); 1520215116Sdes if ((which & OPTIONS_EXTENSIONS) != 0 && 1521215116Sdes (certflags_flags & CERTOPT_PORT_FWD) != 0) 1522215116Sdes add_flag_option(c, "permit-port-forwarding"); 1523215116Sdes if ((which & OPTIONS_EXTENSIONS) != 0 && 1524215116Sdes (certflags_flags & CERTOPT_PTY) != 0) 1525215116Sdes add_flag_option(c, "permit-pty"); 1526215116Sdes if ((which & OPTIONS_EXTENSIONS) != 0 && 1527215116Sdes (certflags_flags & CERTOPT_USER_RC) != 0) 1528215116Sdes add_flag_option(c, "permit-user-rc"); 1529215116Sdes if ((which & OPTIONS_CRITICAL) != 0 && 1530215116Sdes certflags_src_addr != NULL) 1531215116Sdes add_string_option(c, "source-address", certflags_src_addr); 1532204917Sdes} 1533204917Sdes 1534215116Sdesstatic Key * 1535215116Sdesload_pkcs11_key(char *path) 1536215116Sdes{ 1537215116Sdes#ifdef ENABLE_PKCS11 1538215116Sdes Key **keys = NULL, *public, *private = NULL; 1539215116Sdes int i, nkeys; 1540215116Sdes 1541215116Sdes if ((public = key_load_public(path, NULL)) == NULL) 1542215116Sdes fatal("Couldn't load CA public key \"%s\"", path); 1543215116Sdes 1544215116Sdes nkeys = pkcs11_add_provider(pkcs11provider, identity_passphrase, &keys); 1545215116Sdes debug3("%s: %d keys", __func__, nkeys); 1546215116Sdes if (nkeys <= 0) 1547215116Sdes fatal("cannot read public key from pkcs11"); 1548215116Sdes for (i = 0; i < nkeys; i++) { 1549215116Sdes if (key_equal_public(public, keys[i])) { 1550215116Sdes private = keys[i]; 1551215116Sdes continue; 1552215116Sdes } 1553215116Sdes key_free(keys[i]); 1554215116Sdes } 1555263970Sdes free(keys); 1556215116Sdes key_free(public); 1557215116Sdes return private; 1558215116Sdes#else 1559215116Sdes fatal("no pkcs11 support"); 1560215116Sdes#endif /* ENABLE_PKCS11 */ 1561215116Sdes} 1562215116Sdes 1563204917Sdesstatic void 1564204917Sdesdo_ca_sign(struct passwd *pw, int argc, char **argv) 1565204917Sdes{ 1566204917Sdes int i, fd; 1567204917Sdes u_int n; 1568204917Sdes Key *ca, *public; 1569204917Sdes char *otmp, *tmp, *cp, *out, *comment, **plist = NULL; 1570204917Sdes FILE *f; 1571215116Sdes int v00 = 0; /* legacy keys */ 1572204917Sdes 1573215116Sdes if (key_type_name != NULL) { 1574215116Sdes switch (key_type_from_name(key_type_name)) { 1575215116Sdes case KEY_RSA_CERT_V00: 1576215116Sdes case KEY_DSA_CERT_V00: 1577215116Sdes v00 = 1; 1578215116Sdes break; 1579215116Sdes case KEY_UNSPEC: 1580215116Sdes if (strcasecmp(key_type_name, "v00") == 0) { 1581215116Sdes v00 = 1; 1582215116Sdes break; 1583215116Sdes } else if (strcasecmp(key_type_name, "v01") == 0) 1584215116Sdes break; 1585215116Sdes /* FALLTHROUGH */ 1586215116Sdes default: 1587215116Sdes fprintf(stderr, "unknown key type %s\n", key_type_name); 1588215116Sdes exit(1); 1589215116Sdes } 1590215116Sdes } 1591215116Sdes 1592215116Sdes pkcs11_init(1); 1593204917Sdes tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); 1594215116Sdes if (pkcs11provider != NULL) { 1595215116Sdes if ((ca = load_pkcs11_key(tmp)) == NULL) 1596215116Sdes fatal("No PKCS#11 key matching %s found", ca_key_path); 1597215116Sdes } else if ((ca = load_identity(tmp)) == NULL) 1598204917Sdes fatal("Couldn't load CA key \"%s\"", tmp); 1599263970Sdes free(tmp); 1600204917Sdes 1601204917Sdes for (i = 0; i < argc; i++) { 1602204917Sdes /* Split list of principals */ 1603204917Sdes n = 0; 1604204917Sdes if (cert_principals != NULL) { 1605204917Sdes otmp = tmp = xstrdup(cert_principals); 1606204917Sdes plist = NULL; 1607204917Sdes for (; (cp = strsep(&tmp, ",")) != NULL; n++) { 1608204917Sdes plist = xrealloc(plist, n + 1, sizeof(*plist)); 1609204917Sdes if (*(plist[n] = xstrdup(cp)) == '\0') 1610204917Sdes fatal("Empty principal name"); 1611204917Sdes } 1612263970Sdes free(otmp); 1613204917Sdes } 1614204917Sdes 1615204917Sdes tmp = tilde_expand_filename(argv[i], pw->pw_uid); 1616204917Sdes if ((public = key_load_public(tmp, &comment)) == NULL) 1617204917Sdes fatal("%s: unable to open \"%s\"", __func__, tmp); 1618221420Sdes if (public->type != KEY_RSA && public->type != KEY_DSA && 1619263970Sdes public->type != KEY_ECDSA && public->type != KEY_ED25519) 1620204917Sdes fatal("%s: key \"%s\" type %s cannot be certified", 1621204917Sdes __func__, tmp, key_type(public)); 1622204917Sdes 1623204917Sdes /* Prepare certificate to sign */ 1624215116Sdes if (key_to_certified(public, v00) != 0) 1625204917Sdes fatal("Could not upgrade key %s to certificate", tmp); 1626204917Sdes public->cert->type = cert_key_type; 1627215116Sdes public->cert->serial = (u_int64_t)cert_serial; 1628204917Sdes public->cert->key_id = xstrdup(cert_key_id); 1629204917Sdes public->cert->nprincipals = n; 1630204917Sdes public->cert->principals = plist; 1631204917Sdes public->cert->valid_after = cert_valid_from; 1632204917Sdes public->cert->valid_before = cert_valid_to; 1633215116Sdes if (v00) { 1634215116Sdes prepare_options_buf(&public->cert->critical, 1635215116Sdes OPTIONS_CRITICAL|OPTIONS_EXTENSIONS); 1636215116Sdes } else { 1637215116Sdes prepare_options_buf(&public->cert->critical, 1638215116Sdes OPTIONS_CRITICAL); 1639215116Sdes prepare_options_buf(&public->cert->extensions, 1640215116Sdes OPTIONS_EXTENSIONS); 1641215116Sdes } 1642204917Sdes public->cert->signature_key = key_from_private(ca); 1643204917Sdes 1644204917Sdes if (key_certify(public, ca) != 0) 1645204917Sdes fatal("Couldn't not certify key %s", tmp); 1646204917Sdes 1647204917Sdes if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0) 1648204917Sdes *cp = '\0'; 1649204917Sdes xasprintf(&out, "%s-cert.pub", tmp); 1650263970Sdes free(tmp); 1651204917Sdes 1652204917Sdes if ((fd = open(out, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) 1653204917Sdes fatal("Could not open \"%s\" for writing: %s", out, 1654204917Sdes strerror(errno)); 1655204917Sdes if ((f = fdopen(fd, "w")) == NULL) 1656204917Sdes fatal("%s: fdopen: %s", __func__, strerror(errno)); 1657204917Sdes if (!key_write(public, f)) 1658204917Sdes fatal("Could not write certified key to %s", out); 1659204917Sdes fprintf(f, " %s\n", comment); 1660204917Sdes fclose(f); 1661204917Sdes 1662215116Sdes if (!quiet) { 1663215116Sdes logit("Signed %s key %s: id \"%s\" serial %llu%s%s " 1664215116Sdes "valid %s", key_cert_type(public), 1665221420Sdes out, public->cert->key_id, 1666221420Sdes (unsigned long long)public->cert->serial, 1667204917Sdes cert_principals != NULL ? " for " : "", 1668204917Sdes cert_principals != NULL ? cert_principals : "", 1669204917Sdes fmt_validity(cert_valid_from, cert_valid_to)); 1670215116Sdes } 1671204917Sdes 1672204917Sdes key_free(public); 1673263970Sdes free(out); 1674204917Sdes } 1675215116Sdes pkcs11_terminate(); 1676204917Sdes exit(0); 1677204917Sdes} 1678204917Sdes 1679204917Sdesstatic u_int64_t 1680204917Sdesparse_relative_time(const char *s, time_t now) 1681204917Sdes{ 1682204917Sdes int64_t mul, secs; 1683204917Sdes 1684204917Sdes mul = *s == '-' ? -1 : 1; 1685204917Sdes 1686204917Sdes if ((secs = convtime(s + 1)) == -1) 1687204917Sdes fatal("Invalid relative certificate time %s", s); 1688204917Sdes if (mul == -1 && secs > now) 1689204917Sdes fatal("Certificate time %s cannot be represented", s); 1690204917Sdes return now + (u_int64_t)(secs * mul); 1691204917Sdes} 1692204917Sdes 1693204917Sdesstatic u_int64_t 1694204917Sdesparse_absolute_time(const char *s) 1695204917Sdes{ 1696204917Sdes struct tm tm; 1697204917Sdes time_t tt; 1698204917Sdes char buf[32], *fmt; 1699204917Sdes 1700204917Sdes /* 1701204917Sdes * POSIX strptime says "The application shall ensure that there 1702204917Sdes * is white-space or other non-alphanumeric characters between 1703204917Sdes * any two conversion specifications" so arrange things this way. 1704204917Sdes */ 1705204917Sdes switch (strlen(s)) { 1706204917Sdes case 8: 1707204917Sdes fmt = "%Y-%m-%d"; 1708204917Sdes snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2s", s, s + 4, s + 6); 1709204917Sdes break; 1710204917Sdes case 14: 1711204917Sdes fmt = "%Y-%m-%dT%H:%M:%S"; 1712204917Sdes snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s:%.2s", 1713204917Sdes s, s + 4, s + 6, s + 8, s + 10, s + 12); 1714204917Sdes break; 1715204917Sdes default: 1716204917Sdes fatal("Invalid certificate time format %s", s); 1717204917Sdes } 1718204917Sdes 1719263970Sdes memset(&tm, 0, sizeof(tm)); 1720204917Sdes if (strptime(buf, fmt, &tm) == NULL) 1721204917Sdes fatal("Invalid certificate time %s", s); 1722204917Sdes if ((tt = mktime(&tm)) < 0) 1723204917Sdes fatal("Certificate time %s cannot be represented", s); 1724204917Sdes return (u_int64_t)tt; 1725204917Sdes} 1726204917Sdes 1727204917Sdesstatic void 1728204917Sdesparse_cert_times(char *timespec) 1729204917Sdes{ 1730204917Sdes char *from, *to; 1731204917Sdes time_t now = time(NULL); 1732204917Sdes int64_t secs; 1733204917Sdes 1734204917Sdes /* +timespec relative to now */ 1735204917Sdes if (*timespec == '+' && strchr(timespec, ':') == NULL) { 1736204917Sdes if ((secs = convtime(timespec + 1)) == -1) 1737204917Sdes fatal("Invalid relative certificate life %s", timespec); 1738204917Sdes cert_valid_to = now + secs; 1739204917Sdes /* 1740204917Sdes * Backdate certificate one minute to avoid problems on hosts 1741204917Sdes * with poorly-synchronised clocks. 1742204917Sdes */ 1743204917Sdes cert_valid_from = ((now - 59)/ 60) * 60; 1744204917Sdes return; 1745204917Sdes } 1746204917Sdes 1747204917Sdes /* 1748204917Sdes * from:to, where 1749204917Sdes * from := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS 1750204917Sdes * to := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS 1751204917Sdes */ 1752204917Sdes from = xstrdup(timespec); 1753204917Sdes to = strchr(from, ':'); 1754204917Sdes if (to == NULL || from == to || *(to + 1) == '\0') 1755204917Sdes fatal("Invalid certificate life specification %s", timespec); 1756204917Sdes *to++ = '\0'; 1757204917Sdes 1758204917Sdes if (*from == '-' || *from == '+') 1759204917Sdes cert_valid_from = parse_relative_time(from, now); 1760204917Sdes else 1761204917Sdes cert_valid_from = parse_absolute_time(from); 1762204917Sdes 1763204917Sdes if (*to == '-' || *to == '+') 1764263970Sdes cert_valid_to = parse_relative_time(to, now); 1765204917Sdes else 1766204917Sdes cert_valid_to = parse_absolute_time(to); 1767204917Sdes 1768204917Sdes if (cert_valid_to <= cert_valid_from) 1769204917Sdes fatal("Empty certificate validity interval"); 1770263970Sdes free(from); 1771204917Sdes} 1772204917Sdes 1773204917Sdesstatic void 1774215116Sdesadd_cert_option(char *opt) 1775204917Sdes{ 1776204917Sdes char *val; 1777204917Sdes 1778247485Sdes if (strcasecmp(opt, "clear") == 0) 1779215116Sdes certflags_flags = 0; 1780204917Sdes else if (strcasecmp(opt, "no-x11-forwarding") == 0) 1781215116Sdes certflags_flags &= ~CERTOPT_X_FWD; 1782204917Sdes else if (strcasecmp(opt, "permit-x11-forwarding") == 0) 1783215116Sdes certflags_flags |= CERTOPT_X_FWD; 1784204917Sdes else if (strcasecmp(opt, "no-agent-forwarding") == 0) 1785215116Sdes certflags_flags &= ~CERTOPT_AGENT_FWD; 1786204917Sdes else if (strcasecmp(opt, "permit-agent-forwarding") == 0) 1787215116Sdes certflags_flags |= CERTOPT_AGENT_FWD; 1788204917Sdes else if (strcasecmp(opt, "no-port-forwarding") == 0) 1789215116Sdes certflags_flags &= ~CERTOPT_PORT_FWD; 1790204917Sdes else if (strcasecmp(opt, "permit-port-forwarding") == 0) 1791215116Sdes certflags_flags |= CERTOPT_PORT_FWD; 1792204917Sdes else if (strcasecmp(opt, "no-pty") == 0) 1793215116Sdes certflags_flags &= ~CERTOPT_PTY; 1794204917Sdes else if (strcasecmp(opt, "permit-pty") == 0) 1795215116Sdes certflags_flags |= CERTOPT_PTY; 1796204917Sdes else if (strcasecmp(opt, "no-user-rc") == 0) 1797215116Sdes certflags_flags &= ~CERTOPT_USER_RC; 1798204917Sdes else if (strcasecmp(opt, "permit-user-rc") == 0) 1799215116Sdes certflags_flags |= CERTOPT_USER_RC; 1800204917Sdes else if (strncasecmp(opt, "force-command=", 14) == 0) { 1801204917Sdes val = opt + 14; 1802204917Sdes if (*val == '\0') 1803215116Sdes fatal("Empty force-command option"); 1804215116Sdes if (certflags_command != NULL) 1805204917Sdes fatal("force-command already specified"); 1806215116Sdes certflags_command = xstrdup(val); 1807204917Sdes } else if (strncasecmp(opt, "source-address=", 15) == 0) { 1808204917Sdes val = opt + 15; 1809204917Sdes if (*val == '\0') 1810215116Sdes fatal("Empty source-address option"); 1811215116Sdes if (certflags_src_addr != NULL) 1812204917Sdes fatal("source-address already specified"); 1813204917Sdes if (addr_match_cidr_list(NULL, val) != 0) 1814204917Sdes fatal("Invalid source-address list"); 1815215116Sdes certflags_src_addr = xstrdup(val); 1816204917Sdes } else 1817215116Sdes fatal("Unsupported certificate option \"%s\"", opt); 1818204917Sdes} 1819204917Sdes 1820204917Sdesstatic void 1821215116Sdesshow_options(const Buffer *optbuf, int v00, int in_critical) 1822215116Sdes{ 1823263970Sdes char *name; 1824263970Sdes u_char *data; 1825215116Sdes u_int dlen; 1826215116Sdes Buffer options, option; 1827215116Sdes 1828215116Sdes buffer_init(&options); 1829215116Sdes buffer_append(&options, buffer_ptr(optbuf), buffer_len(optbuf)); 1830215116Sdes 1831215116Sdes buffer_init(&option); 1832215116Sdes while (buffer_len(&options) != 0) { 1833215116Sdes name = buffer_get_string(&options, NULL); 1834215116Sdes data = buffer_get_string_ptr(&options, &dlen); 1835215116Sdes buffer_append(&option, data, dlen); 1836215116Sdes printf(" %s", name); 1837215116Sdes if ((v00 || !in_critical) && 1838215116Sdes (strcmp(name, "permit-X11-forwarding") == 0 || 1839215116Sdes strcmp(name, "permit-agent-forwarding") == 0 || 1840215116Sdes strcmp(name, "permit-port-forwarding") == 0 || 1841215116Sdes strcmp(name, "permit-pty") == 0 || 1842215116Sdes strcmp(name, "permit-user-rc") == 0)) 1843215116Sdes printf("\n"); 1844215116Sdes else if ((v00 || in_critical) && 1845215116Sdes (strcmp(name, "force-command") == 0 || 1846215116Sdes strcmp(name, "source-address") == 0)) { 1847215116Sdes data = buffer_get_string(&option, NULL); 1848215116Sdes printf(" %s\n", data); 1849263970Sdes free(data); 1850215116Sdes } else { 1851215116Sdes printf(" UNKNOWN OPTION (len %u)\n", 1852215116Sdes buffer_len(&option)); 1853215116Sdes buffer_clear(&option); 1854215116Sdes } 1855263970Sdes free(name); 1856215116Sdes if (buffer_len(&option) != 0) 1857215116Sdes fatal("Option corrupt: extra data at end"); 1858215116Sdes } 1859215116Sdes buffer_free(&option); 1860215116Sdes buffer_free(&options); 1861215116Sdes} 1862215116Sdes 1863215116Sdesstatic void 1864204917Sdesdo_show_cert(struct passwd *pw) 1865204917Sdes{ 1866204917Sdes Key *key; 1867204917Sdes struct stat st; 1868204917Sdes char *key_fp, *ca_fp; 1869215116Sdes u_int i, v00; 1870204917Sdes 1871204917Sdes if (!have_identity) 1872204917Sdes ask_filename(pw, "Enter file in which the key is"); 1873215116Sdes if (stat(identity_file, &st) < 0) 1874215116Sdes fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); 1875204917Sdes if ((key = key_load_public(identity_file, NULL)) == NULL) 1876204917Sdes fatal("%s is not a public key", identity_file); 1877204917Sdes if (!key_is_cert(key)) 1878204917Sdes fatal("%s is not a certificate", identity_file); 1879215116Sdes v00 = key->type == KEY_RSA_CERT_V00 || key->type == KEY_DSA_CERT_V00; 1880215116Sdes 1881204917Sdes key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); 1882204917Sdes ca_fp = key_fingerprint(key->cert->signature_key, 1883204917Sdes SSH_FP_MD5, SSH_FP_HEX); 1884204917Sdes 1885204917Sdes printf("%s:\n", identity_file); 1886215116Sdes printf(" Type: %s %s certificate\n", key_ssh_name(key), 1887215116Sdes key_cert_type(key)); 1888215116Sdes printf(" Public key: %s %s\n", key_type(key), key_fp); 1889215116Sdes printf(" Signing CA: %s %s\n", 1890204917Sdes key_type(key->cert->signature_key), ca_fp); 1891215116Sdes printf(" Key ID: \"%s\"\n", key->cert->key_id); 1892221420Sdes if (!v00) { 1893221420Sdes printf(" Serial: %llu\n", 1894221420Sdes (unsigned long long)key->cert->serial); 1895221420Sdes } 1896204917Sdes printf(" Valid: %s\n", 1897204917Sdes fmt_validity(key->cert->valid_after, key->cert->valid_before)); 1898204917Sdes printf(" Principals: "); 1899204917Sdes if (key->cert->nprincipals == 0) 1900204917Sdes printf("(none)\n"); 1901204917Sdes else { 1902204917Sdes for (i = 0; i < key->cert->nprincipals; i++) 1903204917Sdes printf("\n %s", 1904204917Sdes key->cert->principals[i]); 1905204917Sdes printf("\n"); 1906204917Sdes } 1907215116Sdes printf(" Critical Options: "); 1908215116Sdes if (buffer_len(&key->cert->critical) == 0) 1909204917Sdes printf("(none)\n"); 1910204917Sdes else { 1911204917Sdes printf("\n"); 1912215116Sdes show_options(&key->cert->critical, v00, 1); 1913215116Sdes } 1914215116Sdes if (!v00) { 1915215116Sdes printf(" Extensions: "); 1916215116Sdes if (buffer_len(&key->cert->extensions) == 0) 1917215116Sdes printf("(none)\n"); 1918215116Sdes else { 1919215116Sdes printf("\n"); 1920215116Sdes show_options(&key->cert->extensions, v00, 0); 1921204917Sdes } 1922204917Sdes } 1923204917Sdes exit(0); 1924204917Sdes} 1925204917Sdes 1926204917Sdesstatic void 1927251135Sdesload_krl(const char *path, struct ssh_krl **krlp) 1928251135Sdes{ 1929251135Sdes Buffer krlbuf; 1930251135Sdes int fd; 1931251135Sdes 1932251135Sdes buffer_init(&krlbuf); 1933251135Sdes if ((fd = open(path, O_RDONLY)) == -1) 1934251135Sdes fatal("open %s: %s", path, strerror(errno)); 1935251135Sdes if (!key_load_file(fd, path, &krlbuf)) 1936251135Sdes fatal("Unable to load KRL"); 1937251135Sdes close(fd); 1938251135Sdes /* XXX check sigs */ 1939251135Sdes if (ssh_krl_from_blob(&krlbuf, krlp, NULL, 0) != 0 || 1940251135Sdes *krlp == NULL) 1941251135Sdes fatal("Invalid KRL file"); 1942251135Sdes buffer_free(&krlbuf); 1943251135Sdes} 1944251135Sdes 1945251135Sdesstatic void 1946251135Sdesupdate_krl_from_file(struct passwd *pw, const char *file, const Key *ca, 1947251135Sdes struct ssh_krl *krl) 1948251135Sdes{ 1949251135Sdes Key *key = NULL; 1950251135Sdes u_long lnum = 0; 1951251135Sdes char *path, *cp, *ep, line[SSH_MAX_PUBKEY_BYTES]; 1952251135Sdes unsigned long long serial, serial2; 1953251135Sdes int i, was_explicit_key, was_sha1, r; 1954251135Sdes FILE *krl_spec; 1955251135Sdes 1956251135Sdes path = tilde_expand_filename(file, pw->pw_uid); 1957251135Sdes if (strcmp(path, "-") == 0) { 1958251135Sdes krl_spec = stdin; 1959251135Sdes free(path); 1960251135Sdes path = xstrdup("(standard input)"); 1961251135Sdes } else if ((krl_spec = fopen(path, "r")) == NULL) 1962251135Sdes fatal("fopen %s: %s", path, strerror(errno)); 1963251135Sdes 1964251135Sdes if (!quiet) 1965251135Sdes printf("Revoking from %s\n", path); 1966251135Sdes while (read_keyfile_line(krl_spec, path, line, sizeof(line), 1967251135Sdes &lnum) == 0) { 1968251135Sdes was_explicit_key = was_sha1 = 0; 1969251135Sdes cp = line + strspn(line, " \t"); 1970251135Sdes /* Trim trailing space, comments and strip \n */ 1971251135Sdes for (i = 0, r = -1; cp[i] != '\0'; i++) { 1972251135Sdes if (cp[i] == '#' || cp[i] == '\n') { 1973251135Sdes cp[i] = '\0'; 1974251135Sdes break; 1975251135Sdes } 1976251135Sdes if (cp[i] == ' ' || cp[i] == '\t') { 1977251135Sdes /* Remember the start of a span of whitespace */ 1978251135Sdes if (r == -1) 1979251135Sdes r = i; 1980251135Sdes } else 1981251135Sdes r = -1; 1982251135Sdes } 1983251135Sdes if (r != -1) 1984251135Sdes cp[r] = '\0'; 1985251135Sdes if (*cp == '\0') 1986251135Sdes continue; 1987251135Sdes if (strncasecmp(cp, "serial:", 7) == 0) { 1988251135Sdes if (ca == NULL) { 1989263970Sdes fatal("revoking certificates by serial number " 1990251135Sdes "requires specification of a CA key"); 1991251135Sdes } 1992251135Sdes cp += 7; 1993251135Sdes cp = cp + strspn(cp, " \t"); 1994251135Sdes errno = 0; 1995251135Sdes serial = strtoull(cp, &ep, 0); 1996251135Sdes if (*cp == '\0' || (*ep != '\0' && *ep != '-')) 1997251135Sdes fatal("%s:%lu: invalid serial \"%s\"", 1998251135Sdes path, lnum, cp); 1999251135Sdes if (errno == ERANGE && serial == ULLONG_MAX) 2000251135Sdes fatal("%s:%lu: serial out of range", 2001251135Sdes path, lnum); 2002251135Sdes serial2 = serial; 2003251135Sdes if (*ep == '-') { 2004251135Sdes cp = ep + 1; 2005251135Sdes errno = 0; 2006251135Sdes serial2 = strtoull(cp, &ep, 0); 2007251135Sdes if (*cp == '\0' || *ep != '\0') 2008251135Sdes fatal("%s:%lu: invalid serial \"%s\"", 2009251135Sdes path, lnum, cp); 2010251135Sdes if (errno == ERANGE && serial2 == ULLONG_MAX) 2011251135Sdes fatal("%s:%lu: serial out of range", 2012251135Sdes path, lnum); 2013251135Sdes if (serial2 <= serial) 2014251135Sdes fatal("%s:%lu: invalid serial range " 2015251135Sdes "%llu:%llu", path, lnum, 2016251135Sdes (unsigned long long)serial, 2017251135Sdes (unsigned long long)serial2); 2018251135Sdes } 2019251135Sdes if (ssh_krl_revoke_cert_by_serial_range(krl, 2020251135Sdes ca, serial, serial2) != 0) { 2021251135Sdes fatal("%s: revoke serial failed", 2022251135Sdes __func__); 2023251135Sdes } 2024251135Sdes } else if (strncasecmp(cp, "id:", 3) == 0) { 2025251135Sdes if (ca == NULL) { 2026263970Sdes fatal("revoking certificates by key ID " 2027251135Sdes "requires specification of a CA key"); 2028251135Sdes } 2029251135Sdes cp += 3; 2030251135Sdes cp = cp + strspn(cp, " \t"); 2031251135Sdes if (ssh_krl_revoke_cert_by_key_id(krl, ca, cp) != 0) 2032251135Sdes fatal("%s: revoke key ID failed", __func__); 2033251135Sdes } else { 2034251135Sdes if (strncasecmp(cp, "key:", 4) == 0) { 2035251135Sdes cp += 4; 2036251135Sdes cp = cp + strspn(cp, " \t"); 2037251135Sdes was_explicit_key = 1; 2038251135Sdes } else if (strncasecmp(cp, "sha1:", 5) == 0) { 2039251135Sdes cp += 5; 2040251135Sdes cp = cp + strspn(cp, " \t"); 2041251135Sdes was_sha1 = 1; 2042251135Sdes } else { 2043251135Sdes /* 2044251135Sdes * Just try to process the line as a key. 2045251135Sdes * Parsing will fail if it isn't. 2046251135Sdes */ 2047251135Sdes } 2048251135Sdes if ((key = key_new(KEY_UNSPEC)) == NULL) 2049251135Sdes fatal("key_new"); 2050251135Sdes if (key_read(key, &cp) != 1) 2051251135Sdes fatal("%s:%lu: invalid key", path, lnum); 2052251135Sdes if (was_explicit_key) 2053251135Sdes r = ssh_krl_revoke_key_explicit(krl, key); 2054251135Sdes else if (was_sha1) 2055251135Sdes r = ssh_krl_revoke_key_sha1(krl, key); 2056251135Sdes else 2057251135Sdes r = ssh_krl_revoke_key(krl, key); 2058251135Sdes if (r != 0) 2059251135Sdes fatal("%s: revoke key failed", __func__); 2060251135Sdes key_free(key); 2061251135Sdes } 2062251135Sdes } 2063251135Sdes if (strcmp(path, "-") != 0) 2064251135Sdes fclose(krl_spec); 2065263970Sdes free(path); 2066251135Sdes} 2067251135Sdes 2068251135Sdesstatic void 2069251135Sdesdo_gen_krl(struct passwd *pw, int updating, int argc, char **argv) 2070251135Sdes{ 2071251135Sdes struct ssh_krl *krl; 2072251135Sdes struct stat sb; 2073251135Sdes Key *ca = NULL; 2074251135Sdes int fd, i; 2075251135Sdes char *tmp; 2076251135Sdes Buffer kbuf; 2077251135Sdes 2078251135Sdes if (*identity_file == '\0') 2079251135Sdes fatal("KRL generation requires an output file"); 2080251135Sdes if (stat(identity_file, &sb) == -1) { 2081251135Sdes if (errno != ENOENT) 2082251135Sdes fatal("Cannot access KRL \"%s\": %s", 2083251135Sdes identity_file, strerror(errno)); 2084251135Sdes if (updating) 2085251135Sdes fatal("KRL \"%s\" does not exist", identity_file); 2086251135Sdes } 2087251135Sdes if (ca_key_path != NULL) { 2088251135Sdes tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); 2089251135Sdes if ((ca = key_load_public(tmp, NULL)) == NULL) 2090251135Sdes fatal("Cannot load CA public key %s", tmp); 2091263970Sdes free(tmp); 2092251135Sdes } 2093251135Sdes 2094251135Sdes if (updating) 2095251135Sdes load_krl(identity_file, &krl); 2096251135Sdes else if ((krl = ssh_krl_init()) == NULL) 2097251135Sdes fatal("couldn't create KRL"); 2098251135Sdes 2099251135Sdes if (cert_serial != 0) 2100251135Sdes ssh_krl_set_version(krl, cert_serial); 2101251135Sdes if (identity_comment != NULL) 2102251135Sdes ssh_krl_set_comment(krl, identity_comment); 2103251135Sdes 2104251135Sdes for (i = 0; i < argc; i++) 2105251135Sdes update_krl_from_file(pw, argv[i], ca, krl); 2106251135Sdes 2107251135Sdes buffer_init(&kbuf); 2108251135Sdes if (ssh_krl_to_blob(krl, &kbuf, NULL, 0) != 0) 2109251135Sdes fatal("Couldn't generate KRL"); 2110251135Sdes if ((fd = open(identity_file, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) 2111251135Sdes fatal("open %s: %s", identity_file, strerror(errno)); 2112251135Sdes if (atomicio(vwrite, fd, buffer_ptr(&kbuf), buffer_len(&kbuf)) != 2113251135Sdes buffer_len(&kbuf)) 2114251135Sdes fatal("write %s: %s", identity_file, strerror(errno)); 2115251135Sdes close(fd); 2116251135Sdes buffer_free(&kbuf); 2117251135Sdes ssh_krl_free(krl); 2118263970Sdes if (ca != NULL) 2119263970Sdes key_free(ca); 2120251135Sdes} 2121251135Sdes 2122251135Sdesstatic void 2123251135Sdesdo_check_krl(struct passwd *pw, int argc, char **argv) 2124251135Sdes{ 2125251135Sdes int i, r, ret = 0; 2126251135Sdes char *comment; 2127251135Sdes struct ssh_krl *krl; 2128251135Sdes Key *k; 2129251135Sdes 2130251135Sdes if (*identity_file == '\0') 2131251135Sdes fatal("KRL checking requires an input file"); 2132251135Sdes load_krl(identity_file, &krl); 2133251135Sdes for (i = 0; i < argc; i++) { 2134251135Sdes if ((k = key_load_public(argv[i], &comment)) == NULL) 2135251135Sdes fatal("Cannot load public key %s", argv[i]); 2136251135Sdes r = ssh_krl_check_key(krl, k); 2137251135Sdes printf("%s%s%s%s: %s\n", argv[i], 2138251135Sdes *comment ? " (" : "", comment, *comment ? ")" : "", 2139251135Sdes r == 0 ? "ok" : "REVOKED"); 2140251135Sdes if (r != 0) 2141251135Sdes ret = 1; 2142251135Sdes key_free(k); 2143251135Sdes free(comment); 2144251135Sdes } 2145251135Sdes ssh_krl_free(krl); 2146251135Sdes exit(ret); 2147251135Sdes} 2148251135Sdes 2149251135Sdesstatic void 215057429Smarkmusage(void) 215157429Smarkm{ 2152181111Sdes fprintf(stderr, "usage: %s [options]\n", __progname); 215392555Sdes fprintf(stderr, "Options:\n"); 2154247485Sdes fprintf(stderr, " -A Generate non-existent host keys for all key types.\n"); 2155263970Sdes fprintf(stderr, " -a number Number of KDF rounds for new key format or moduli primality tests.\n"); 2156149749Sdes fprintf(stderr, " -B Show bubblebabble digest of key file.\n"); 215792555Sdes fprintf(stderr, " -b bits Number of bits in the key to create.\n"); 2158149749Sdes fprintf(stderr, " -C comment Provide new comment.\n"); 215992555Sdes fprintf(stderr, " -c Change comment in private and public key files.\n"); 2160204917Sdes#ifdef ENABLE_PKCS11 2161204917Sdes fprintf(stderr, " -D pkcs11 Download public key from pkcs11 token.\n"); 2162204917Sdes#endif 2163215116Sdes fprintf(stderr, " -e Export OpenSSH to foreign format key file.\n"); 2164149749Sdes fprintf(stderr, " -F hostname Find hostname in known hosts file.\n"); 216592555Sdes fprintf(stderr, " -f filename Filename of the key file.\n"); 2166149749Sdes fprintf(stderr, " -G file Generate candidates for DH-GEX moduli.\n"); 2167124208Sdes fprintf(stderr, " -g Use generic DNS resource record format.\n"); 2168149749Sdes fprintf(stderr, " -H Hash names in known_hosts file.\n"); 2169204917Sdes fprintf(stderr, " -h Generate host certificate instead of a user certificate.\n"); 2170204917Sdes fprintf(stderr, " -I key_id Key identifier to include in certificate.\n"); 2171215116Sdes fprintf(stderr, " -i Import foreign format to OpenSSH key file.\n"); 2172247485Sdes fprintf(stderr, " -J number Screen this number of moduli lines.\n"); 2173247485Sdes fprintf(stderr, " -j number Start screening moduli at specified line.\n"); 2174247485Sdes fprintf(stderr, " -K checkpt Write checkpoints to this file.\n"); 2175251135Sdes fprintf(stderr, " -k Generate a KRL file.\n"); 2176204917Sdes fprintf(stderr, " -L Print the contents of a certificate.\n"); 217792555Sdes fprintf(stderr, " -l Show fingerprint of key file.\n"); 2178149749Sdes fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n"); 2179215116Sdes fprintf(stderr, " -m key_fmt Conversion format for -e/-i (PEM|PKCS8|RFC4716).\n"); 2180215116Sdes fprintf(stderr, " -N phrase Provide new passphrase.\n"); 2181204917Sdes fprintf(stderr, " -n name,... User/host principal names to include in certificate\n"); 2182215116Sdes fprintf(stderr, " -O option Specify a certificate option.\n"); 2183263970Sdes fprintf(stderr, " -o Enforce new private key format.\n"); 2184149749Sdes fprintf(stderr, " -P phrase Provide old passphrase.\n"); 218592555Sdes fprintf(stderr, " -p Change passphrase of private key file.\n"); 2186251135Sdes fprintf(stderr, " -Q Test whether key(s) are revoked in KRL.\n"); 218792555Sdes fprintf(stderr, " -q Quiet.\n"); 2188149749Sdes fprintf(stderr, " -R hostname Remove host from known_hosts file.\n"); 2189149749Sdes fprintf(stderr, " -r hostname Print DNS resource record.\n"); 2190215116Sdes fprintf(stderr, " -S start Start point (hex) for generating DH-GEX moduli.\n"); 2191204917Sdes fprintf(stderr, " -s ca_key Certify keys with CA key.\n"); 2192149749Sdes fprintf(stderr, " -T file Screen candidates for DH-GEX moduli.\n"); 219392555Sdes fprintf(stderr, " -t type Specify type of key to create.\n"); 2194251135Sdes fprintf(stderr, " -u Update KRL rather than creating a new one.\n"); 2195204917Sdes fprintf(stderr, " -V from:to Specify certificate validity interval.\n"); 2196149749Sdes fprintf(stderr, " -v Verbose.\n"); 2197149749Sdes fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n"); 2198149749Sdes fprintf(stderr, " -y Read private key file and print public key.\n"); 2199263970Sdes fprintf(stderr, " -Z cipher Specify a cipher for new private key format.\n"); 2200215116Sdes fprintf(stderr, " -z serial Specify a serial number.\n"); 220192555Sdes 220257429Smarkm exit(1); 220357429Smarkm} 220457429Smarkm 220557429Smarkm/* 220657429Smarkm * Main program for key management. 220757429Smarkm */ 220857429Smarkmint 2209181111Sdesmain(int argc, char **argv) 221057429Smarkm{ 221192555Sdes char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; 2212247485Sdes char *checkpoint = NULL; 2213251135Sdes char out_file[MAXPATHLEN], *ep, *rr_hostname = NULL; 221476259Sgreen Key *private, *public; 221557429Smarkm struct passwd *pw; 221657429Smarkm struct stat st; 2217204917Sdes int opt, type, fd; 2218263970Sdes u_int32_t memory = 0, generator_wanted = 0; 2219124208Sdes int do_gen_candidates = 0, do_screen_candidates = 0; 2220251135Sdes int gen_all_hostkeys = 0, gen_krl = 0, update_krl = 0, check_krl = 0; 2221247485Sdes unsigned long start_lineno = 0, lines_to_process = 0; 2222124208Sdes BIGNUM *start = NULL; 222357429Smarkm FILE *f; 2224149749Sdes const char *errstr; 222576259Sgreen 222657429Smarkm extern int optind; 222757429Smarkm extern char *optarg; 222857429Smarkm 2229157016Sdes /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 2230157016Sdes sanitise_stdfd(); 2231157016Sdes 2232181111Sdes __progname = ssh_get_progname(argv[0]); 223398937Sdes 2234221420Sdes OpenSSL_add_all_algorithms(); 2235181111Sdes log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1); 2236124208Sdes 2237106121Sdes seed_rng(); 223860573Skris 223957429Smarkm /* we need this for the home * directory. */ 224057429Smarkm pw = getpwuid(getuid()); 224157429Smarkm if (!pw) { 2242263970Sdes printf("No user exists for uid %lu\n", (u_long)getuid()); 224357429Smarkm exit(1); 224457429Smarkm } 224560573Skris if (gethostname(hostname, sizeof(hostname)) < 0) { 224660573Skris perror("gethostname"); 224760573Skris exit(1); 224860573Skris } 224957429Smarkm 2250263970Sdes /* Remaining characters: EUYdw */ 2251263970Sdes while ((opt = getopt(argc, argv, "ABHLQXceghiklopquvxy" 2252263970Sdes "C:D:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:a:b:f:g:j:m:n:r:s:t:z:")) != -1) { 225357429Smarkm switch (opt) { 2254247485Sdes case 'A': 2255247485Sdes gen_all_hostkeys = 1; 2256247485Sdes break; 225757429Smarkm case 'b': 2258221420Sdes bits = (u_int32_t)strtonum(optarg, 256, 32768, &errstr); 2259149749Sdes if (errstr) 2260149749Sdes fatal("Bits has bad value %s (%s)", 2261149749Sdes optarg, errstr); 226257429Smarkm break; 2263146998Sdes case 'F': 2264146998Sdes find_host = 1; 2265146998Sdes rr_hostname = optarg; 2266146998Sdes break; 2267146998Sdes case 'H': 2268146998Sdes hash_hosts = 1; 2269146998Sdes break; 2270204917Sdes case 'I': 2271204917Sdes cert_key_id = optarg; 2272204917Sdes break; 2273247485Sdes case 'J': 2274247485Sdes lines_to_process = strtoul(optarg, NULL, 10); 2275247485Sdes break; 2276247485Sdes case 'j': 2277247485Sdes start_lineno = strtoul(optarg, NULL, 10); 2278247485Sdes break; 2279146998Sdes case 'R': 2280146998Sdes delete_host = 1; 2281146998Sdes rr_hostname = optarg; 2282146998Sdes break; 2283204917Sdes case 'L': 2284204917Sdes show_cert = 1; 2285204917Sdes break; 228657429Smarkm case 'l': 228757429Smarkm print_fingerprint = 1; 228857429Smarkm break; 228976259Sgreen case 'B': 229076259Sgreen print_bubblebabble = 1; 229176259Sgreen break; 2292215116Sdes case 'm': 2293215116Sdes if (strcasecmp(optarg, "RFC4716") == 0 || 2294215116Sdes strcasecmp(optarg, "ssh2") == 0) { 2295215116Sdes convert_format = FMT_RFC4716; 2296215116Sdes break; 2297215116Sdes } 2298215116Sdes if (strcasecmp(optarg, "PKCS8") == 0) { 2299215116Sdes convert_format = FMT_PKCS8; 2300215116Sdes break; 2301215116Sdes } 2302215116Sdes if (strcasecmp(optarg, "PEM") == 0) { 2303215116Sdes convert_format = FMT_PEM; 2304215116Sdes break; 2305215116Sdes } 2306215116Sdes fatal("Unsupported conversion format \"%s\"", optarg); 2307204917Sdes case 'n': 2308204917Sdes cert_principals = optarg; 2309204917Sdes break; 2310263970Sdes case 'o': 2311263970Sdes use_new_format = 1; 2312263970Sdes break; 231357429Smarkm case 'p': 231457429Smarkm change_passphrase = 1; 231557429Smarkm break; 231657429Smarkm case 'c': 231757429Smarkm change_comment = 1; 231857429Smarkm break; 231957429Smarkm case 'f': 2320149749Sdes if (strlcpy(identity_file, optarg, sizeof(identity_file)) >= 2321149749Sdes sizeof(identity_file)) 2322149749Sdes fatal("Identity filename too long"); 232357429Smarkm have_identity = 1; 232457429Smarkm break; 2325124208Sdes case 'g': 2326124208Sdes print_generic = 1; 2327124208Sdes break; 232857429Smarkm case 'P': 232957429Smarkm identity_passphrase = optarg; 233057429Smarkm break; 233157429Smarkm case 'N': 233257429Smarkm identity_new_passphrase = optarg; 233357429Smarkm break; 2334251135Sdes case 'Q': 2335251135Sdes check_krl = 1; 2336251135Sdes break; 2337204917Sdes case 'O': 2338215116Sdes add_cert_option(optarg); 2339204917Sdes break; 2340263970Sdes case 'Z': 2341263970Sdes new_format_cipher = optarg; 2342263970Sdes break; 234357429Smarkm case 'C': 234457429Smarkm identity_comment = optarg; 234557429Smarkm break; 234657429Smarkm case 'q': 234757429Smarkm quiet = 1; 234857429Smarkm break; 234976259Sgreen case 'e': 235060573Skris case 'x': 235176259Sgreen /* export key */ 2352215116Sdes convert_to = 1; 235360573Skris break; 2354204917Sdes case 'h': 2355204917Sdes cert_key_type = SSH2_CERT_TYPE_HOST; 2356215116Sdes certflags_flags = 0; 2357204917Sdes break; 2358251135Sdes case 'k': 2359251135Sdes gen_krl = 1; 2360251135Sdes break; 236176259Sgreen case 'i': 236260573Skris case 'X': 236376259Sgreen /* import key */ 2364215116Sdes convert_from = 1; 236560573Skris break; 236660573Skris case 'y': 236760573Skris print_public = 1; 236860573Skris break; 2369204917Sdes case 's': 2370204917Sdes ca_key_path = optarg; 2371204917Sdes break; 237276259Sgreen case 't': 237376259Sgreen key_type_name = optarg; 237476259Sgreen break; 237592555Sdes case 'D': 2376204917Sdes pkcs11provider = optarg; 237792555Sdes break; 2378251135Sdes case 'u': 2379251135Sdes update_krl = 1; 2380251135Sdes break; 2381126274Sdes case 'v': 2382126274Sdes if (log_level == SYSLOG_LEVEL_INFO) 2383126274Sdes log_level = SYSLOG_LEVEL_DEBUG1; 2384126274Sdes else { 2385137015Sdes if (log_level >= SYSLOG_LEVEL_DEBUG1 && 2386126274Sdes log_level < SYSLOG_LEVEL_DEBUG3) 2387126274Sdes log_level++; 2388126274Sdes } 2389126274Sdes break; 2390124208Sdes case 'r': 2391146998Sdes rr_hostname = optarg; 2392124208Sdes break; 2393124208Sdes case 'W': 2394162852Sdes generator_wanted = (u_int32_t)strtonum(optarg, 1, 2395162852Sdes UINT_MAX, &errstr); 2396149749Sdes if (errstr) 2397149749Sdes fatal("Desired generator has bad value: %s (%s)", 2398149749Sdes optarg, errstr); 2399124208Sdes break; 2400124208Sdes case 'a': 2401263970Sdes rounds = (int)strtonum(optarg, 1, INT_MAX, &errstr); 2402149749Sdes if (errstr) 2403263970Sdes fatal("Invalid number: %s (%s)", 2404149749Sdes optarg, errstr); 2405124208Sdes break; 2406124208Sdes case 'M': 2407162852Sdes memory = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr); 2408215116Sdes if (errstr) 2409149749Sdes fatal("Memory limit is %s: %s", errstr, optarg); 2410124208Sdes break; 2411124208Sdes case 'G': 2412124208Sdes do_gen_candidates = 1; 2413149749Sdes if (strlcpy(out_file, optarg, sizeof(out_file)) >= 2414149749Sdes sizeof(out_file)) 2415149749Sdes fatal("Output filename too long"); 2416124208Sdes break; 2417124208Sdes case 'T': 2418124208Sdes do_screen_candidates = 1; 2419149749Sdes if (strlcpy(out_file, optarg, sizeof(out_file)) >= 2420149749Sdes sizeof(out_file)) 2421149749Sdes fatal("Output filename too long"); 2422124208Sdes break; 2423247485Sdes case 'K': 2424247485Sdes if (strlen(optarg) >= MAXPATHLEN) 2425247485Sdes fatal("Checkpoint filename too long"); 2426247485Sdes checkpoint = xstrdup(optarg); 2427247485Sdes break; 2428124208Sdes case 'S': 2429124208Sdes /* XXX - also compare length against bits */ 2430124208Sdes if (BN_hex2bn(&start, optarg) == 0) 2431124208Sdes fatal("Invalid start point."); 2432124208Sdes break; 2433204917Sdes case 'V': 2434204917Sdes parse_cert_times(optarg); 2435204917Sdes break; 2436215116Sdes case 'z': 2437251135Sdes errno = 0; 2438251135Sdes cert_serial = strtoull(optarg, &ep, 10); 2439251135Sdes if (*optarg < '0' || *optarg > '9' || *ep != '\0' || 2440251135Sdes (errno == ERANGE && cert_serial == ULLONG_MAX)) 2441251135Sdes fatal("Invalid serial number \"%s\"", optarg); 2442215116Sdes break; 244357429Smarkm case '?': 244457429Smarkm default: 244557429Smarkm usage(); 244657429Smarkm } 244757429Smarkm } 2448126274Sdes 2449126274Sdes /* reinit */ 2450181111Sdes log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1); 2451126274Sdes 2452204917Sdes argv += optind; 2453204917Sdes argc -= optind; 2454204917Sdes 2455204917Sdes if (ca_key_path != NULL) { 2456251135Sdes if (argc < 1 && !gen_krl) { 2457204917Sdes printf("Too few arguments.\n"); 2458204917Sdes usage(); 2459204917Sdes } 2460251135Sdes } else if (argc > 0 && !gen_krl && !check_krl) { 246157429Smarkm printf("Too many arguments.\n"); 246257429Smarkm usage(); 246357429Smarkm } 246457429Smarkm if (change_passphrase && change_comment) { 246557429Smarkm printf("Can only have one of -p and -c.\n"); 246657429Smarkm usage(); 246757429Smarkm } 2468181111Sdes if (print_fingerprint && (delete_host || hash_hosts)) { 2469251135Sdes printf("Cannot use -l with -H or -R.\n"); 2470181111Sdes usage(); 2471181111Sdes } 2472251135Sdes if (gen_krl) { 2473251135Sdes do_gen_krl(pw, update_krl, argc, argv); 2474251135Sdes return (0); 2475251135Sdes } 2476251135Sdes if (check_krl) { 2477251135Sdes do_check_krl(pw, argc, argv); 2478251135Sdes return (0); 2479251135Sdes } 2480204917Sdes if (ca_key_path != NULL) { 2481204917Sdes if (cert_key_id == NULL) 2482204917Sdes fatal("Must specify key id (-I) when certifying"); 2483204917Sdes do_ca_sign(pw, argc, argv); 2484204917Sdes } 2485204917Sdes if (show_cert) 2486204917Sdes do_show_cert(pw); 2487146998Sdes if (delete_host || hash_hosts || find_host) 2488146998Sdes do_known_hosts(pw, rr_hostname); 2489251135Sdes if (pkcs11provider != NULL) 2490251135Sdes do_download(pw); 249176259Sgreen if (print_fingerprint || print_bubblebabble) 249257429Smarkm do_fingerprint(pw); 249357429Smarkm if (change_passphrase) 249457429Smarkm do_change_passphrase(pw); 2495106121Sdes if (change_comment) 2496106121Sdes do_change_comment(pw); 2497215116Sdes if (convert_to) 2498215116Sdes do_convert_to(pw); 2499215116Sdes if (convert_from) 2500215116Sdes do_convert_from(pw); 250160573Skris if (print_public) 250260573Skris do_print_public(pw); 2503146998Sdes if (rr_hostname != NULL) { 2504162852Sdes unsigned int n = 0; 2505162852Sdes 2506162852Sdes if (have_identity) { 2507162852Sdes n = do_print_resource_record(pw, 2508162852Sdes identity_file, rr_hostname); 2509162852Sdes if (n == 0) { 2510162852Sdes perror(identity_file); 2511162852Sdes exit(1); 2512162852Sdes } 2513162852Sdes exit(0); 2514162852Sdes } else { 2515162852Sdes 2516162852Sdes n += do_print_resource_record(pw, 2517162852Sdes _PATH_HOST_RSA_KEY_FILE, rr_hostname); 2518162852Sdes n += do_print_resource_record(pw, 2519162852Sdes _PATH_HOST_DSA_KEY_FILE, rr_hostname); 2520247485Sdes n += do_print_resource_record(pw, 2521247485Sdes _PATH_HOST_ECDSA_KEY_FILE, rr_hostname); 2522162852Sdes 2523162852Sdes if (n == 0) 2524162852Sdes fatal("no keys found."); 2525162852Sdes exit(0); 2526162852Sdes } 2527124208Sdes } 252857429Smarkm 2529124208Sdes if (do_gen_candidates) { 2530124208Sdes FILE *out = fopen(out_file, "w"); 2531126274Sdes 2532124208Sdes if (out == NULL) { 2533124208Sdes error("Couldn't open modulus candidate file \"%s\": %s", 2534124208Sdes out_file, strerror(errno)); 2535124208Sdes return (1); 2536124208Sdes } 2537157016Sdes if (bits == 0) 2538157016Sdes bits = DEFAULT_BITS; 2539124208Sdes if (gen_candidates(out, memory, bits, start) != 0) 2540157016Sdes fatal("modulus candidate generation failed"); 2541124208Sdes 2542124208Sdes return (0); 2543124208Sdes } 2544124208Sdes 2545124208Sdes if (do_screen_candidates) { 2546124208Sdes FILE *in; 2547251135Sdes FILE *out = fopen(out_file, "a"); 2548124208Sdes 2549124208Sdes if (have_identity && strcmp(identity_file, "-") != 0) { 2550124208Sdes if ((in = fopen(identity_file, "r")) == NULL) { 2551124208Sdes fatal("Couldn't open modulus candidate " 2552126274Sdes "file \"%s\": %s", identity_file, 2553124208Sdes strerror(errno)); 2554124208Sdes } 2555124208Sdes } else 2556124208Sdes in = stdin; 2557124208Sdes 2558124208Sdes if (out == NULL) { 2559124208Sdes fatal("Couldn't open moduli file \"%s\": %s", 2560124208Sdes out_file, strerror(errno)); 2561124208Sdes } 2562263970Sdes if (prime_test(in, out, rounds == 0 ? 100 : rounds, 2563263970Sdes generator_wanted, checkpoint, 2564247485Sdes start_lineno, lines_to_process) != 0) 2565157016Sdes fatal("modulus screening failed"); 2566124208Sdes return (0); 2567124208Sdes } 2568124208Sdes 2569247485Sdes if (gen_all_hostkeys) { 2570247485Sdes do_gen_all_hostkeys(pw); 2571247485Sdes return (0); 2572247485Sdes } 2573247485Sdes 2574157016Sdes if (key_type_name == NULL) 2575157016Sdes key_type_name = "rsa"; 2576157016Sdes 257776259Sgreen type = key_type_from_name(key_type_name); 2578247485Sdes type_bits_valid(type, &bits); 2579247485Sdes 258076259Sgreen if (!quiet) 258176259Sgreen printf("Generating public/private %s key pair.\n", key_type_name); 258276259Sgreen private = key_generate(type, bits); 258376259Sgreen if (private == NULL) { 2584192595Sdes fprintf(stderr, "key_generate failed\n"); 258576259Sgreen exit(1); 258676259Sgreen } 258776259Sgreen public = key_from_private(private); 258857429Smarkm 258957429Smarkm if (!have_identity) 259057429Smarkm ask_filename(pw, "Enter file in which to save the key"); 259157429Smarkm 2592157016Sdes /* Create ~/.ssh directory if it doesn't already exist. */ 2593215116Sdes snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", 2594215116Sdes pw->pw_dir, _PATH_SSH_USER_DIR); 2595215116Sdes if (strstr(identity_file, dotsshdir) != NULL) { 2596215116Sdes if (stat(dotsshdir, &st) < 0) { 2597215116Sdes if (errno != ENOENT) { 2598215116Sdes error("Could not stat %s: %s", dotsshdir, 2599215116Sdes strerror(errno)); 2600215116Sdes } else if (mkdir(dotsshdir, 0700) < 0) { 2601215116Sdes error("Could not create directory '%s': %s", 2602215116Sdes dotsshdir, strerror(errno)); 2603215116Sdes } else if (!quiet) 2604215116Sdes printf("Created directory '%s'.\n", dotsshdir); 2605215116Sdes } 260657429Smarkm } 260757429Smarkm /* If the file already exists, ask the user to confirm. */ 260857429Smarkm if (stat(identity_file, &st) >= 0) { 260957429Smarkm char yesno[3]; 261057429Smarkm printf("%s already exists.\n", identity_file); 261157429Smarkm printf("Overwrite (y/n)? "); 261257429Smarkm fflush(stdout); 261357429Smarkm if (fgets(yesno, sizeof(yesno), stdin) == NULL) 261457429Smarkm exit(1); 261557429Smarkm if (yesno[0] != 'y' && yesno[0] != 'Y') 261657429Smarkm exit(1); 261757429Smarkm } 261857429Smarkm /* Ask for a passphrase (twice). */ 261957429Smarkm if (identity_passphrase) 262057429Smarkm passphrase1 = xstrdup(identity_passphrase); 262157429Smarkm else if (identity_new_passphrase) 262257429Smarkm passphrase1 = xstrdup(identity_new_passphrase); 262357429Smarkm else { 262457429Smarkmpassphrase_again: 262557429Smarkm passphrase1 = 262692555Sdes read_passphrase("Enter passphrase (empty for no " 262792555Sdes "passphrase): ", RP_ALLOW_STDIN); 262892555Sdes passphrase2 = read_passphrase("Enter same passphrase again: ", 262992555Sdes RP_ALLOW_STDIN); 263057429Smarkm if (strcmp(passphrase1, passphrase2) != 0) { 263192555Sdes /* 263292555Sdes * The passphrases do not match. Clear them and 263392555Sdes * retry. 263492555Sdes */ 2635263970Sdes explicit_bzero(passphrase1, strlen(passphrase1)); 2636263970Sdes explicit_bzero(passphrase2, strlen(passphrase2)); 2637263970Sdes free(passphrase1); 2638263970Sdes free(passphrase2); 263957429Smarkm printf("Passphrases do not match. Try again.\n"); 264057429Smarkm goto passphrase_again; 264157429Smarkm } 264257429Smarkm /* Clear the other copy of the passphrase. */ 2643263970Sdes explicit_bzero(passphrase2, strlen(passphrase2)); 2644263970Sdes free(passphrase2); 264557429Smarkm } 264657429Smarkm 264757429Smarkm if (identity_comment) { 264857429Smarkm strlcpy(comment, identity_comment, sizeof(comment)); 264957429Smarkm } else { 2650192595Sdes /* Create default comment field for the passphrase. */ 265157429Smarkm snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); 265257429Smarkm } 265357429Smarkm 265457429Smarkm /* Save the key with the given passphrase and comment. */ 2655263970Sdes if (!key_save_private(private, identity_file, passphrase1, comment, 2656263970Sdes use_new_format, new_format_cipher, rounds)) { 265776259Sgreen printf("Saving the key failed: %s.\n", identity_file); 2658263970Sdes explicit_bzero(passphrase1, strlen(passphrase1)); 2659263970Sdes free(passphrase1); 266057429Smarkm exit(1); 266157429Smarkm } 266257429Smarkm /* Clear the passphrase. */ 2663263970Sdes explicit_bzero(passphrase1, strlen(passphrase1)); 2664263970Sdes free(passphrase1); 266557429Smarkm 266657429Smarkm /* Clear the private key and the random number generator. */ 266776259Sgreen key_free(private); 266857429Smarkm 266957429Smarkm if (!quiet) 267057429Smarkm printf("Your identification has been saved in %s.\n", identity_file); 267157429Smarkm 267257429Smarkm strlcat(identity_file, ".pub", sizeof(identity_file)); 267376259Sgreen fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); 267476259Sgreen if (fd == -1) { 267557429Smarkm printf("Could not save your public key in %s\n", identity_file); 267657429Smarkm exit(1); 267757429Smarkm } 267876259Sgreen f = fdopen(fd, "w"); 267976259Sgreen if (f == NULL) { 2680192595Sdes printf("fdopen %s failed\n", identity_file); 268176259Sgreen exit(1); 268276259Sgreen } 268360573Skris if (!key_write(public, f)) 2684192595Sdes fprintf(stderr, "write key failed\n"); 268560573Skris fprintf(f, " %s\n", comment); 268657429Smarkm fclose(f); 268757429Smarkm 268857429Smarkm if (!quiet) { 268976259Sgreen char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX); 2690181111Sdes char *ra = key_fingerprint(public, SSH_FP_MD5, 2691181111Sdes SSH_FP_RANDOMART); 269260573Skris printf("Your public key has been saved in %s.\n", 269360573Skris identity_file); 269457429Smarkm printf("The key fingerprint is:\n"); 269576259Sgreen printf("%s %s\n", fp, comment); 2696181111Sdes printf("The key's randomart image is:\n"); 2697181111Sdes printf("%s\n", ra); 2698263970Sdes free(ra); 2699263970Sdes free(fp); 270057429Smarkm } 270160573Skris 270260573Skris key_free(public); 270357429Smarkm exit(0); 270457429Smarkm} 2705