1*cb5eb4f1SPeter Avalos /* $OpenBSD: ssh-keygen.c,v 1.173 2009/02/21 19:32:04 tobias Exp $ */ 218de8d7fSPeter Avalos /* 318de8d7fSPeter Avalos * Author: Tatu Ylonen <ylo@cs.hut.fi> 418de8d7fSPeter Avalos * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 518de8d7fSPeter Avalos * All rights reserved 618de8d7fSPeter Avalos * Identity and host key generation and maintenance. 718de8d7fSPeter Avalos * 818de8d7fSPeter Avalos * As far as I am concerned, the code I have written for this software 918de8d7fSPeter Avalos * can be used freely for any purpose. Any derived versions of this 1018de8d7fSPeter Avalos * software must be clearly marked as such, and if the derived work is 1118de8d7fSPeter Avalos * incompatible with the protocol description in the RFC file, it must be 1218de8d7fSPeter Avalos * called by a name other than "ssh" or "Secure Shell". 1318de8d7fSPeter Avalos */ 1418de8d7fSPeter Avalos 1518de8d7fSPeter Avalos #include "includes.h" 1618de8d7fSPeter Avalos 1718de8d7fSPeter Avalos #include <sys/types.h> 1818de8d7fSPeter Avalos #include <sys/socket.h> 1918de8d7fSPeter Avalos #include <sys/stat.h> 2018de8d7fSPeter Avalos #include <sys/param.h> 2118de8d7fSPeter Avalos 2218de8d7fSPeter Avalos #include <openssl/evp.h> 2318de8d7fSPeter Avalos #include <openssl/pem.h> 2418de8d7fSPeter Avalos #include "openbsd-compat/openssl-compat.h" 2518de8d7fSPeter Avalos 2618de8d7fSPeter Avalos #include <errno.h> 2718de8d7fSPeter Avalos #include <fcntl.h> 2818de8d7fSPeter Avalos #include <netdb.h> 2918de8d7fSPeter Avalos #ifdef HAVE_PATHS_H 3018de8d7fSPeter Avalos # include <paths.h> 3118de8d7fSPeter Avalos #endif 3218de8d7fSPeter Avalos #include <pwd.h> 3318de8d7fSPeter Avalos #include <stdarg.h> 3418de8d7fSPeter Avalos #include <stdio.h> 3518de8d7fSPeter Avalos #include <stdlib.h> 3618de8d7fSPeter Avalos #include <string.h> 3718de8d7fSPeter Avalos #include <unistd.h> 3818de8d7fSPeter Avalos 3918de8d7fSPeter Avalos #include "xmalloc.h" 4018de8d7fSPeter Avalos #include "key.h" 4118de8d7fSPeter Avalos #include "rsa.h" 4218de8d7fSPeter Avalos #include "authfile.h" 4318de8d7fSPeter Avalos #include "uuencode.h" 4418de8d7fSPeter Avalos #include "buffer.h" 4518de8d7fSPeter Avalos #include "pathnames.h" 4618de8d7fSPeter Avalos #include "log.h" 4718de8d7fSPeter Avalos #include "misc.h" 4818de8d7fSPeter Avalos #include "match.h" 4918de8d7fSPeter Avalos #include "hostfile.h" 5018de8d7fSPeter Avalos #include "dns.h" 5118de8d7fSPeter Avalos 5218de8d7fSPeter Avalos #ifdef SMARTCARD 5318de8d7fSPeter Avalos #include "scard.h" 5418de8d7fSPeter Avalos #endif 5518de8d7fSPeter Avalos 5618de8d7fSPeter Avalos /* Number of bits in the RSA/DSA key. This value can be set on the command line. */ 5718de8d7fSPeter Avalos #define DEFAULT_BITS 2048 5818de8d7fSPeter Avalos #define DEFAULT_BITS_DSA 1024 5918de8d7fSPeter Avalos u_int32_t bits = 0; 6018de8d7fSPeter Avalos 6118de8d7fSPeter Avalos /* 6218de8d7fSPeter Avalos * Flag indicating that we just want to change the passphrase. This can be 6318de8d7fSPeter Avalos * set on the command line. 6418de8d7fSPeter Avalos */ 6518de8d7fSPeter Avalos int change_passphrase = 0; 6618de8d7fSPeter Avalos 6718de8d7fSPeter Avalos /* 6818de8d7fSPeter Avalos * Flag indicating that we just want to change the comment. This can be set 6918de8d7fSPeter Avalos * on the command line. 7018de8d7fSPeter Avalos */ 7118de8d7fSPeter Avalos int change_comment = 0; 7218de8d7fSPeter Avalos 7318de8d7fSPeter Avalos int quiet = 0; 7418de8d7fSPeter Avalos 7518de8d7fSPeter Avalos int log_level = SYSLOG_LEVEL_INFO; 7618de8d7fSPeter Avalos 7718de8d7fSPeter Avalos /* Flag indicating that we want to hash a known_hosts file */ 7818de8d7fSPeter Avalos int hash_hosts = 0; 7918de8d7fSPeter Avalos /* Flag indicating that we want lookup a host in known_hosts file */ 8018de8d7fSPeter Avalos int find_host = 0; 8118de8d7fSPeter Avalos /* Flag indicating that we want to delete a host from a known_hosts file */ 8218de8d7fSPeter Avalos int delete_host = 0; 8318de8d7fSPeter Avalos 8418de8d7fSPeter Avalos /* Flag indicating that we just want to see the key fingerprint */ 8518de8d7fSPeter Avalos int print_fingerprint = 0; 8618de8d7fSPeter Avalos int print_bubblebabble = 0; 8718de8d7fSPeter Avalos 8818de8d7fSPeter Avalos /* The identity file name, given on the command line or entered by the user. */ 8918de8d7fSPeter Avalos char identity_file[1024]; 9018de8d7fSPeter Avalos int have_identity = 0; 9118de8d7fSPeter Avalos 9218de8d7fSPeter Avalos /* This is set to the passphrase if given on the command line. */ 9318de8d7fSPeter Avalos char *identity_passphrase = NULL; 9418de8d7fSPeter Avalos 9518de8d7fSPeter Avalos /* This is set to the new passphrase if given on the command line. */ 9618de8d7fSPeter Avalos char *identity_new_passphrase = NULL; 9718de8d7fSPeter Avalos 9818de8d7fSPeter Avalos /* This is set to the new comment if given on the command line. */ 9918de8d7fSPeter Avalos char *identity_comment = NULL; 10018de8d7fSPeter Avalos 10118de8d7fSPeter Avalos /* Dump public key file in format used by real and the original SSH 2 */ 10218de8d7fSPeter Avalos int convert_to_ssh2 = 0; 10318de8d7fSPeter Avalos int convert_from_ssh2 = 0; 10418de8d7fSPeter Avalos int print_public = 0; 10518de8d7fSPeter Avalos int print_generic = 0; 10618de8d7fSPeter Avalos 10718de8d7fSPeter Avalos char *key_type_name = NULL; 10818de8d7fSPeter Avalos 10918de8d7fSPeter Avalos /* argv0 */ 11018de8d7fSPeter Avalos extern char *__progname; 11118de8d7fSPeter Avalos 11218de8d7fSPeter Avalos char hostname[MAXHOSTNAMELEN]; 11318de8d7fSPeter Avalos 11418de8d7fSPeter Avalos /* moduli.c */ 11518de8d7fSPeter Avalos int gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *); 11618de8d7fSPeter Avalos int prime_test(FILE *, FILE *, u_int32_t, u_int32_t); 11718de8d7fSPeter Avalos 11818de8d7fSPeter Avalos static void 11918de8d7fSPeter Avalos ask_filename(struct passwd *pw, const char *prompt) 12018de8d7fSPeter Avalos { 12118de8d7fSPeter Avalos char buf[1024]; 12218de8d7fSPeter Avalos char *name = NULL; 12318de8d7fSPeter Avalos 12418de8d7fSPeter Avalos if (key_type_name == NULL) 12518de8d7fSPeter Avalos name = _PATH_SSH_CLIENT_ID_RSA; 12618de8d7fSPeter Avalos else { 12718de8d7fSPeter Avalos switch (key_type_from_name(key_type_name)) { 12818de8d7fSPeter Avalos case KEY_RSA1: 12918de8d7fSPeter Avalos name = _PATH_SSH_CLIENT_IDENTITY; 13018de8d7fSPeter Avalos break; 13118de8d7fSPeter Avalos case KEY_DSA: 13218de8d7fSPeter Avalos name = _PATH_SSH_CLIENT_ID_DSA; 13318de8d7fSPeter Avalos break; 13418de8d7fSPeter Avalos case KEY_RSA: 13518de8d7fSPeter Avalos name = _PATH_SSH_CLIENT_ID_RSA; 13618de8d7fSPeter Avalos break; 13718de8d7fSPeter Avalos default: 138*cb5eb4f1SPeter Avalos fprintf(stderr, "bad key type\n"); 13918de8d7fSPeter Avalos exit(1); 14018de8d7fSPeter Avalos break; 14118de8d7fSPeter Avalos } 14218de8d7fSPeter Avalos } 14318de8d7fSPeter Avalos snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name); 14418de8d7fSPeter Avalos fprintf(stderr, "%s (%s): ", prompt, identity_file); 14518de8d7fSPeter Avalos if (fgets(buf, sizeof(buf), stdin) == NULL) 14618de8d7fSPeter Avalos exit(1); 14718de8d7fSPeter Avalos buf[strcspn(buf, "\n")] = '\0'; 14818de8d7fSPeter Avalos if (strcmp(buf, "") != 0) 14918de8d7fSPeter Avalos strlcpy(identity_file, buf, sizeof(identity_file)); 15018de8d7fSPeter Avalos have_identity = 1; 15118de8d7fSPeter Avalos } 15218de8d7fSPeter Avalos 15318de8d7fSPeter Avalos static Key * 15418de8d7fSPeter Avalos load_identity(char *filename) 15518de8d7fSPeter Avalos { 15618de8d7fSPeter Avalos char *pass; 15718de8d7fSPeter Avalos Key *prv; 15818de8d7fSPeter Avalos 15918de8d7fSPeter Avalos prv = key_load_private(filename, "", NULL); 16018de8d7fSPeter Avalos if (prv == NULL) { 16118de8d7fSPeter Avalos if (identity_passphrase) 16218de8d7fSPeter Avalos pass = xstrdup(identity_passphrase); 16318de8d7fSPeter Avalos else 16418de8d7fSPeter Avalos pass = read_passphrase("Enter passphrase: ", 16518de8d7fSPeter Avalos RP_ALLOW_STDIN); 16618de8d7fSPeter Avalos prv = key_load_private(filename, pass, NULL); 16718de8d7fSPeter Avalos memset(pass, 0, strlen(pass)); 16818de8d7fSPeter Avalos xfree(pass); 16918de8d7fSPeter Avalos } 17018de8d7fSPeter Avalos return prv; 17118de8d7fSPeter Avalos } 17218de8d7fSPeter Avalos 17318de8d7fSPeter Avalos #define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----" 17418de8d7fSPeter Avalos #define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----" 17518de8d7fSPeter Avalos #define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----" 17618de8d7fSPeter Avalos #define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb 17718de8d7fSPeter Avalos 17818de8d7fSPeter Avalos static void 17918de8d7fSPeter Avalos do_convert_to_ssh2(struct passwd *pw) 18018de8d7fSPeter Avalos { 18118de8d7fSPeter Avalos Key *k; 18218de8d7fSPeter Avalos u_int len; 18318de8d7fSPeter Avalos u_char *blob; 18418de8d7fSPeter Avalos struct stat st; 18518de8d7fSPeter Avalos 18618de8d7fSPeter Avalos if (!have_identity) 18718de8d7fSPeter Avalos ask_filename(pw, "Enter file in which the key is"); 18818de8d7fSPeter Avalos if (stat(identity_file, &st) < 0) { 18918de8d7fSPeter Avalos perror(identity_file); 19018de8d7fSPeter Avalos exit(1); 19118de8d7fSPeter Avalos } 19218de8d7fSPeter Avalos if ((k = key_load_public(identity_file, NULL)) == NULL) { 19318de8d7fSPeter Avalos if ((k = load_identity(identity_file)) == NULL) { 19418de8d7fSPeter Avalos fprintf(stderr, "load failed\n"); 19518de8d7fSPeter Avalos exit(1); 19618de8d7fSPeter Avalos } 19718de8d7fSPeter Avalos } 19818de8d7fSPeter Avalos if (k->type == KEY_RSA1) { 19918de8d7fSPeter Avalos fprintf(stderr, "version 1 keys are not supported\n"); 20018de8d7fSPeter Avalos exit(1); 20118de8d7fSPeter Avalos } 20218de8d7fSPeter Avalos if (key_to_blob(k, &blob, &len) <= 0) { 20318de8d7fSPeter Avalos fprintf(stderr, "key_to_blob failed\n"); 20418de8d7fSPeter Avalos exit(1); 20518de8d7fSPeter Avalos } 20618de8d7fSPeter Avalos fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN); 20718de8d7fSPeter Avalos fprintf(stdout, 20818de8d7fSPeter Avalos "Comment: \"%u-bit %s, converted from OpenSSH by %s@%s\"\n", 20918de8d7fSPeter Avalos key_size(k), key_type(k), 21018de8d7fSPeter Avalos pw->pw_name, hostname); 21118de8d7fSPeter Avalos dump_base64(stdout, blob, len); 21218de8d7fSPeter Avalos fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END); 21318de8d7fSPeter Avalos key_free(k); 21418de8d7fSPeter Avalos xfree(blob); 21518de8d7fSPeter Avalos exit(0); 21618de8d7fSPeter Avalos } 21718de8d7fSPeter Avalos 21818de8d7fSPeter Avalos static void 21918de8d7fSPeter Avalos buffer_get_bignum_bits(Buffer *b, BIGNUM *value) 22018de8d7fSPeter Avalos { 22118de8d7fSPeter Avalos u_int bignum_bits = buffer_get_int(b); 22218de8d7fSPeter Avalos u_int bytes = (bignum_bits + 7) / 8; 22318de8d7fSPeter Avalos 22418de8d7fSPeter Avalos if (buffer_len(b) < bytes) 22518de8d7fSPeter Avalos fatal("buffer_get_bignum_bits: input buffer too small: " 22618de8d7fSPeter Avalos "need %d have %d", bytes, buffer_len(b)); 22718de8d7fSPeter Avalos if (BN_bin2bn(buffer_ptr(b), bytes, value) == NULL) 22818de8d7fSPeter Avalos fatal("buffer_get_bignum_bits: BN_bin2bn failed"); 22918de8d7fSPeter Avalos buffer_consume(b, bytes); 23018de8d7fSPeter Avalos } 23118de8d7fSPeter Avalos 23218de8d7fSPeter Avalos static Key * 23318de8d7fSPeter Avalos do_convert_private_ssh2_from_blob(u_char *blob, u_int blen) 23418de8d7fSPeter Avalos { 23518de8d7fSPeter Avalos Buffer b; 23618de8d7fSPeter Avalos Key *key = NULL; 23718de8d7fSPeter Avalos char *type, *cipher; 23818de8d7fSPeter Avalos u_char *sig, data[] = "abcde12345"; 23918de8d7fSPeter Avalos int magic, rlen, ktype, i1, i2, i3, i4; 24018de8d7fSPeter Avalos u_int slen; 24118de8d7fSPeter Avalos u_long e; 24218de8d7fSPeter Avalos 24318de8d7fSPeter Avalos buffer_init(&b); 24418de8d7fSPeter Avalos buffer_append(&b, blob, blen); 24518de8d7fSPeter Avalos 24618de8d7fSPeter Avalos magic = buffer_get_int(&b); 24718de8d7fSPeter Avalos if (magic != SSH_COM_PRIVATE_KEY_MAGIC) { 24818de8d7fSPeter Avalos error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC); 24918de8d7fSPeter Avalos buffer_free(&b); 25018de8d7fSPeter Avalos return NULL; 25118de8d7fSPeter Avalos } 25218de8d7fSPeter Avalos i1 = buffer_get_int(&b); 25318de8d7fSPeter Avalos type = buffer_get_string(&b, NULL); 25418de8d7fSPeter Avalos cipher = buffer_get_string(&b, NULL); 25518de8d7fSPeter Avalos i2 = buffer_get_int(&b); 25618de8d7fSPeter Avalos i3 = buffer_get_int(&b); 25718de8d7fSPeter Avalos i4 = buffer_get_int(&b); 25818de8d7fSPeter Avalos debug("ignore (%d %d %d %d)", i1, i2, i3, i4); 25918de8d7fSPeter Avalos if (strcmp(cipher, "none") != 0) { 26018de8d7fSPeter Avalos error("unsupported cipher %s", cipher); 26118de8d7fSPeter Avalos xfree(cipher); 26218de8d7fSPeter Avalos buffer_free(&b); 26318de8d7fSPeter Avalos xfree(type); 26418de8d7fSPeter Avalos return NULL; 26518de8d7fSPeter Avalos } 26618de8d7fSPeter Avalos xfree(cipher); 26718de8d7fSPeter Avalos 26818de8d7fSPeter Avalos if (strstr(type, "dsa")) { 26918de8d7fSPeter Avalos ktype = KEY_DSA; 27018de8d7fSPeter Avalos } else if (strstr(type, "rsa")) { 27118de8d7fSPeter Avalos ktype = KEY_RSA; 27218de8d7fSPeter Avalos } else { 27318de8d7fSPeter Avalos buffer_free(&b); 27418de8d7fSPeter Avalos xfree(type); 27518de8d7fSPeter Avalos return NULL; 27618de8d7fSPeter Avalos } 27718de8d7fSPeter Avalos key = key_new_private(ktype); 27818de8d7fSPeter Avalos xfree(type); 27918de8d7fSPeter Avalos 28018de8d7fSPeter Avalos switch (key->type) { 28118de8d7fSPeter Avalos case KEY_DSA: 28218de8d7fSPeter Avalos buffer_get_bignum_bits(&b, key->dsa->p); 28318de8d7fSPeter Avalos buffer_get_bignum_bits(&b, key->dsa->g); 28418de8d7fSPeter Avalos buffer_get_bignum_bits(&b, key->dsa->q); 28518de8d7fSPeter Avalos buffer_get_bignum_bits(&b, key->dsa->pub_key); 28618de8d7fSPeter Avalos buffer_get_bignum_bits(&b, key->dsa->priv_key); 28718de8d7fSPeter Avalos break; 28818de8d7fSPeter Avalos case KEY_RSA: 28918de8d7fSPeter Avalos e = buffer_get_char(&b); 29018de8d7fSPeter Avalos debug("e %lx", e); 29118de8d7fSPeter Avalos if (e < 30) { 29218de8d7fSPeter Avalos e <<= 8; 29318de8d7fSPeter Avalos e += buffer_get_char(&b); 29418de8d7fSPeter Avalos debug("e %lx", e); 29518de8d7fSPeter Avalos e <<= 8; 29618de8d7fSPeter Avalos e += buffer_get_char(&b); 29718de8d7fSPeter Avalos debug("e %lx", e); 29818de8d7fSPeter Avalos } 29918de8d7fSPeter Avalos if (!BN_set_word(key->rsa->e, e)) { 30018de8d7fSPeter Avalos buffer_free(&b); 30118de8d7fSPeter Avalos key_free(key); 30218de8d7fSPeter Avalos return NULL; 30318de8d7fSPeter Avalos } 30418de8d7fSPeter Avalos buffer_get_bignum_bits(&b, key->rsa->d); 30518de8d7fSPeter Avalos buffer_get_bignum_bits(&b, key->rsa->n); 30618de8d7fSPeter Avalos buffer_get_bignum_bits(&b, key->rsa->iqmp); 30718de8d7fSPeter Avalos buffer_get_bignum_bits(&b, key->rsa->q); 30818de8d7fSPeter Avalos buffer_get_bignum_bits(&b, key->rsa->p); 30918de8d7fSPeter Avalos rsa_generate_additional_parameters(key->rsa); 31018de8d7fSPeter Avalos break; 31118de8d7fSPeter Avalos } 31218de8d7fSPeter Avalos rlen = buffer_len(&b); 31318de8d7fSPeter Avalos if (rlen != 0) 31418de8d7fSPeter Avalos error("do_convert_private_ssh2_from_blob: " 31518de8d7fSPeter Avalos "remaining bytes in key blob %d", rlen); 31618de8d7fSPeter Avalos buffer_free(&b); 31718de8d7fSPeter Avalos 31818de8d7fSPeter Avalos /* try the key */ 31918de8d7fSPeter Avalos key_sign(key, &sig, &slen, data, sizeof(data)); 32018de8d7fSPeter Avalos key_verify(key, sig, slen, data, sizeof(data)); 32118de8d7fSPeter Avalos xfree(sig); 32218de8d7fSPeter Avalos return key; 32318de8d7fSPeter Avalos } 32418de8d7fSPeter Avalos 32518de8d7fSPeter Avalos static int 32618de8d7fSPeter Avalos get_line(FILE *fp, char *line, size_t len) 32718de8d7fSPeter Avalos { 32818de8d7fSPeter Avalos int c; 32918de8d7fSPeter Avalos size_t pos = 0; 33018de8d7fSPeter Avalos 33118de8d7fSPeter Avalos line[0] = '\0'; 33218de8d7fSPeter Avalos while ((c = fgetc(fp)) != EOF) { 33318de8d7fSPeter Avalos if (pos >= len - 1) { 33418de8d7fSPeter Avalos fprintf(stderr, "input line too long.\n"); 33518de8d7fSPeter Avalos exit(1); 33618de8d7fSPeter Avalos } 33718de8d7fSPeter Avalos switch (c) { 33818de8d7fSPeter Avalos case '\r': 33918de8d7fSPeter Avalos c = fgetc(fp); 34018de8d7fSPeter Avalos if (c != EOF && c != '\n' && ungetc(c, fp) == EOF) { 34118de8d7fSPeter Avalos fprintf(stderr, "unget: %s\n", strerror(errno)); 34218de8d7fSPeter Avalos exit(1); 34318de8d7fSPeter Avalos } 34418de8d7fSPeter Avalos return pos; 34518de8d7fSPeter Avalos case '\n': 34618de8d7fSPeter Avalos return pos; 34718de8d7fSPeter Avalos } 34818de8d7fSPeter Avalos line[pos++] = c; 34918de8d7fSPeter Avalos line[pos] = '\0'; 35018de8d7fSPeter Avalos } 35118de8d7fSPeter Avalos /* We reached EOF */ 35218de8d7fSPeter Avalos return -1; 35318de8d7fSPeter Avalos } 35418de8d7fSPeter Avalos 35518de8d7fSPeter Avalos static void 35618de8d7fSPeter Avalos do_convert_from_ssh2(struct passwd *pw) 35718de8d7fSPeter Avalos { 35818de8d7fSPeter Avalos Key *k; 35918de8d7fSPeter Avalos int blen; 36018de8d7fSPeter Avalos u_int len; 36118de8d7fSPeter Avalos char line[1024]; 36218de8d7fSPeter Avalos u_char blob[8096]; 36318de8d7fSPeter Avalos char encoded[8096]; 36418de8d7fSPeter Avalos struct stat st; 36518de8d7fSPeter Avalos int escaped = 0, private = 0, ok; 36618de8d7fSPeter Avalos FILE *fp; 36718de8d7fSPeter Avalos 36818de8d7fSPeter Avalos if (!have_identity) 36918de8d7fSPeter Avalos ask_filename(pw, "Enter file in which the key is"); 37018de8d7fSPeter Avalos if (stat(identity_file, &st) < 0) { 37118de8d7fSPeter Avalos perror(identity_file); 37218de8d7fSPeter Avalos exit(1); 37318de8d7fSPeter Avalos } 37418de8d7fSPeter Avalos fp = fopen(identity_file, "r"); 37518de8d7fSPeter Avalos if (fp == NULL) { 37618de8d7fSPeter Avalos perror(identity_file); 37718de8d7fSPeter Avalos exit(1); 37818de8d7fSPeter Avalos } 37918de8d7fSPeter Avalos encoded[0] = '\0'; 38018de8d7fSPeter Avalos while ((blen = get_line(fp, line, sizeof(line))) != -1) { 38118de8d7fSPeter Avalos if (line[blen - 1] == '\\') 38218de8d7fSPeter Avalos escaped++; 38318de8d7fSPeter Avalos if (strncmp(line, "----", 4) == 0 || 38418de8d7fSPeter Avalos strstr(line, ": ") != NULL) { 38518de8d7fSPeter Avalos if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL) 38618de8d7fSPeter Avalos private = 1; 38718de8d7fSPeter Avalos if (strstr(line, " END ") != NULL) { 38818de8d7fSPeter Avalos break; 38918de8d7fSPeter Avalos } 39018de8d7fSPeter Avalos /* fprintf(stderr, "ignore: %s", line); */ 39118de8d7fSPeter Avalos continue; 39218de8d7fSPeter Avalos } 39318de8d7fSPeter Avalos if (escaped) { 39418de8d7fSPeter Avalos escaped--; 39518de8d7fSPeter Avalos /* fprintf(stderr, "escaped: %s", line); */ 39618de8d7fSPeter Avalos continue; 39718de8d7fSPeter Avalos } 39818de8d7fSPeter Avalos strlcat(encoded, line, sizeof(encoded)); 39918de8d7fSPeter Avalos } 40018de8d7fSPeter Avalos len = strlen(encoded); 40118de8d7fSPeter Avalos if (((len % 4) == 3) && 40218de8d7fSPeter Avalos (encoded[len-1] == '=') && 40318de8d7fSPeter Avalos (encoded[len-2] == '=') && 40418de8d7fSPeter Avalos (encoded[len-3] == '=')) 40518de8d7fSPeter Avalos encoded[len-3] = '\0'; 40618de8d7fSPeter Avalos blen = uudecode(encoded, blob, sizeof(blob)); 40718de8d7fSPeter Avalos if (blen < 0) { 40818de8d7fSPeter Avalos fprintf(stderr, "uudecode failed.\n"); 40918de8d7fSPeter Avalos exit(1); 41018de8d7fSPeter Avalos } 41118de8d7fSPeter Avalos k = private ? 41218de8d7fSPeter Avalos do_convert_private_ssh2_from_blob(blob, blen) : 41318de8d7fSPeter Avalos key_from_blob(blob, blen); 41418de8d7fSPeter Avalos if (k == NULL) { 41518de8d7fSPeter Avalos fprintf(stderr, "decode blob failed.\n"); 41618de8d7fSPeter Avalos exit(1); 41718de8d7fSPeter Avalos } 41818de8d7fSPeter Avalos ok = private ? 41918de8d7fSPeter Avalos (k->type == KEY_DSA ? 42018de8d7fSPeter Avalos PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) : 42118de8d7fSPeter Avalos PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) : 42218de8d7fSPeter Avalos key_write(k, stdout); 42318de8d7fSPeter Avalos if (!ok) { 424*cb5eb4f1SPeter Avalos fprintf(stderr, "key write failed\n"); 42518de8d7fSPeter Avalos exit(1); 42618de8d7fSPeter Avalos } 42718de8d7fSPeter Avalos key_free(k); 42818de8d7fSPeter Avalos if (!private) 42918de8d7fSPeter Avalos fprintf(stdout, "\n"); 43018de8d7fSPeter Avalos fclose(fp); 43118de8d7fSPeter Avalos exit(0); 43218de8d7fSPeter Avalos } 43318de8d7fSPeter Avalos 43418de8d7fSPeter Avalos static void 43518de8d7fSPeter Avalos do_print_public(struct passwd *pw) 43618de8d7fSPeter Avalos { 43718de8d7fSPeter Avalos Key *prv; 43818de8d7fSPeter Avalos struct stat st; 43918de8d7fSPeter Avalos 44018de8d7fSPeter Avalos if (!have_identity) 44118de8d7fSPeter Avalos ask_filename(pw, "Enter file in which the key is"); 44218de8d7fSPeter Avalos if (stat(identity_file, &st) < 0) { 44318de8d7fSPeter Avalos perror(identity_file); 44418de8d7fSPeter Avalos exit(1); 44518de8d7fSPeter Avalos } 44618de8d7fSPeter Avalos prv = load_identity(identity_file); 44718de8d7fSPeter Avalos if (prv == NULL) { 44818de8d7fSPeter Avalos fprintf(stderr, "load failed\n"); 44918de8d7fSPeter Avalos exit(1); 45018de8d7fSPeter Avalos } 45118de8d7fSPeter Avalos if (!key_write(prv, stdout)) 45218de8d7fSPeter Avalos fprintf(stderr, "key_write failed"); 45318de8d7fSPeter Avalos key_free(prv); 45418de8d7fSPeter Avalos fprintf(stdout, "\n"); 45518de8d7fSPeter Avalos exit(0); 45618de8d7fSPeter Avalos } 45718de8d7fSPeter Avalos 45818de8d7fSPeter Avalos #ifdef SMARTCARD 45918de8d7fSPeter Avalos static void 46018de8d7fSPeter Avalos do_upload(struct passwd *pw, const char *sc_reader_id) 46118de8d7fSPeter Avalos { 46218de8d7fSPeter Avalos Key *prv = NULL; 46318de8d7fSPeter Avalos struct stat st; 46418de8d7fSPeter Avalos int ret; 46518de8d7fSPeter Avalos 46618de8d7fSPeter Avalos if (!have_identity) 46718de8d7fSPeter Avalos ask_filename(pw, "Enter file in which the key is"); 46818de8d7fSPeter Avalos if (stat(identity_file, &st) < 0) { 46918de8d7fSPeter Avalos perror(identity_file); 47018de8d7fSPeter Avalos exit(1); 47118de8d7fSPeter Avalos } 47218de8d7fSPeter Avalos prv = load_identity(identity_file); 47318de8d7fSPeter Avalos if (prv == NULL) { 47418de8d7fSPeter Avalos error("load failed"); 47518de8d7fSPeter Avalos exit(1); 47618de8d7fSPeter Avalos } 47718de8d7fSPeter Avalos ret = sc_put_key(prv, sc_reader_id); 47818de8d7fSPeter Avalos key_free(prv); 47918de8d7fSPeter Avalos if (ret < 0) 48018de8d7fSPeter Avalos exit(1); 48118de8d7fSPeter Avalos logit("loading key done"); 48218de8d7fSPeter Avalos exit(0); 48318de8d7fSPeter Avalos } 48418de8d7fSPeter Avalos 48518de8d7fSPeter Avalos static void 48618de8d7fSPeter Avalos do_download(struct passwd *pw, const char *sc_reader_id) 48718de8d7fSPeter Avalos { 48818de8d7fSPeter Avalos Key **keys = NULL; 48918de8d7fSPeter Avalos int i; 49018de8d7fSPeter Avalos 49118de8d7fSPeter Avalos keys = sc_get_keys(sc_reader_id, NULL); 49218de8d7fSPeter Avalos if (keys == NULL) 49318de8d7fSPeter Avalos fatal("cannot read public key from smartcard"); 49418de8d7fSPeter Avalos for (i = 0; keys[i]; i++) { 49518de8d7fSPeter Avalos key_write(keys[i], stdout); 49618de8d7fSPeter Avalos key_free(keys[i]); 49718de8d7fSPeter Avalos fprintf(stdout, "\n"); 49818de8d7fSPeter Avalos } 49918de8d7fSPeter Avalos xfree(keys); 50018de8d7fSPeter Avalos exit(0); 50118de8d7fSPeter Avalos } 50218de8d7fSPeter Avalos #endif /* SMARTCARD */ 50318de8d7fSPeter Avalos 50418de8d7fSPeter Avalos static void 50518de8d7fSPeter Avalos do_fingerprint(struct passwd *pw) 50618de8d7fSPeter Avalos { 50718de8d7fSPeter Avalos FILE *f; 50818de8d7fSPeter Avalos Key *public; 50918de8d7fSPeter Avalos char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra; 51018de8d7fSPeter Avalos int i, skip = 0, num = 0, invalid = 1; 51118de8d7fSPeter Avalos enum fp_rep rep; 51218de8d7fSPeter Avalos enum fp_type fptype; 51318de8d7fSPeter Avalos struct stat st; 51418de8d7fSPeter Avalos 51518de8d7fSPeter Avalos fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; 51618de8d7fSPeter Avalos rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; 51718de8d7fSPeter Avalos 51818de8d7fSPeter Avalos if (!have_identity) 51918de8d7fSPeter Avalos ask_filename(pw, "Enter file in which the key is"); 52018de8d7fSPeter Avalos if (stat(identity_file, &st) < 0) { 52118de8d7fSPeter Avalos perror(identity_file); 52218de8d7fSPeter Avalos exit(1); 52318de8d7fSPeter Avalos } 52418de8d7fSPeter Avalos public = key_load_public(identity_file, &comment); 52518de8d7fSPeter Avalos if (public != NULL) { 52618de8d7fSPeter Avalos fp = key_fingerprint(public, fptype, rep); 52718de8d7fSPeter Avalos ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART); 52818de8d7fSPeter Avalos printf("%u %s %s (%s)\n", key_size(public), fp, comment, 52918de8d7fSPeter Avalos key_type(public)); 53018de8d7fSPeter Avalos if (log_level >= SYSLOG_LEVEL_VERBOSE) 53118de8d7fSPeter Avalos printf("%s\n", ra); 53218de8d7fSPeter Avalos key_free(public); 53318de8d7fSPeter Avalos xfree(comment); 53418de8d7fSPeter Avalos xfree(ra); 53518de8d7fSPeter Avalos xfree(fp); 53618de8d7fSPeter Avalos exit(0); 53718de8d7fSPeter Avalos } 53818de8d7fSPeter Avalos if (comment) { 53918de8d7fSPeter Avalos xfree(comment); 54018de8d7fSPeter Avalos comment = NULL; 54118de8d7fSPeter Avalos } 54218de8d7fSPeter Avalos 54318de8d7fSPeter Avalos f = fopen(identity_file, "r"); 54418de8d7fSPeter Avalos if (f != NULL) { 54518de8d7fSPeter Avalos while (fgets(line, sizeof(line), f)) { 54618de8d7fSPeter Avalos if ((cp = strchr(line, '\n')) == NULL) { 54718de8d7fSPeter Avalos error("line %d too long: %.40s...", 54818de8d7fSPeter Avalos num + 1, line); 54918de8d7fSPeter Avalos skip = 1; 55018de8d7fSPeter Avalos continue; 55118de8d7fSPeter Avalos } 55218de8d7fSPeter Avalos num++; 55318de8d7fSPeter Avalos if (skip) { 55418de8d7fSPeter Avalos skip = 0; 55518de8d7fSPeter Avalos continue; 55618de8d7fSPeter Avalos } 55718de8d7fSPeter Avalos *cp = '\0'; 55818de8d7fSPeter Avalos 55918de8d7fSPeter Avalos /* Skip leading whitespace, empty and comment lines. */ 56018de8d7fSPeter Avalos for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 56118de8d7fSPeter Avalos ; 56218de8d7fSPeter Avalos if (!*cp || *cp == '\n' || *cp == '#') 56318de8d7fSPeter Avalos continue; 56418de8d7fSPeter Avalos i = strtol(cp, &ep, 10); 56518de8d7fSPeter Avalos if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) { 56618de8d7fSPeter Avalos int quoted = 0; 56718de8d7fSPeter Avalos comment = cp; 56818de8d7fSPeter Avalos for (; *cp && (quoted || (*cp != ' ' && 56918de8d7fSPeter Avalos *cp != '\t')); cp++) { 57018de8d7fSPeter Avalos if (*cp == '\\' && cp[1] == '"') 57118de8d7fSPeter Avalos cp++; /* Skip both */ 57218de8d7fSPeter Avalos else if (*cp == '"') 57318de8d7fSPeter Avalos quoted = !quoted; 57418de8d7fSPeter Avalos } 57518de8d7fSPeter Avalos if (!*cp) 57618de8d7fSPeter Avalos continue; 57718de8d7fSPeter Avalos *cp++ = '\0'; 57818de8d7fSPeter Avalos } 57918de8d7fSPeter Avalos ep = cp; 58018de8d7fSPeter Avalos public = key_new(KEY_RSA1); 58118de8d7fSPeter Avalos if (key_read(public, &cp) != 1) { 58218de8d7fSPeter Avalos cp = ep; 58318de8d7fSPeter Avalos key_free(public); 58418de8d7fSPeter Avalos public = key_new(KEY_UNSPEC); 58518de8d7fSPeter Avalos if (key_read(public, &cp) != 1) { 58618de8d7fSPeter Avalos key_free(public); 58718de8d7fSPeter Avalos continue; 58818de8d7fSPeter Avalos } 58918de8d7fSPeter Avalos } 59018de8d7fSPeter Avalos comment = *cp ? cp : comment; 59118de8d7fSPeter Avalos fp = key_fingerprint(public, fptype, rep); 59218de8d7fSPeter Avalos ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART); 59318de8d7fSPeter Avalos printf("%u %s %s (%s)\n", key_size(public), fp, 59418de8d7fSPeter Avalos comment ? comment : "no comment", key_type(public)); 59518de8d7fSPeter Avalos if (log_level >= SYSLOG_LEVEL_VERBOSE) 59618de8d7fSPeter Avalos printf("%s\n", ra); 59718de8d7fSPeter Avalos xfree(ra); 59818de8d7fSPeter Avalos xfree(fp); 59918de8d7fSPeter Avalos key_free(public); 60018de8d7fSPeter Avalos invalid = 0; 60118de8d7fSPeter Avalos } 60218de8d7fSPeter Avalos fclose(f); 60318de8d7fSPeter Avalos } 60418de8d7fSPeter Avalos if (invalid) { 60518de8d7fSPeter Avalos printf("%s is not a public key file.\n", identity_file); 60618de8d7fSPeter Avalos exit(1); 60718de8d7fSPeter Avalos } 60818de8d7fSPeter Avalos exit(0); 60918de8d7fSPeter Avalos } 61018de8d7fSPeter Avalos 61118de8d7fSPeter Avalos static void 61218de8d7fSPeter Avalos print_host(FILE *f, const char *name, Key *public, int hash) 61318de8d7fSPeter Avalos { 61418de8d7fSPeter Avalos if (print_fingerprint) { 61518de8d7fSPeter Avalos enum fp_rep rep; 61618de8d7fSPeter Avalos enum fp_type fptype; 61718de8d7fSPeter Avalos char *fp, *ra; 61818de8d7fSPeter Avalos 61918de8d7fSPeter Avalos fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; 62018de8d7fSPeter Avalos rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; 62118de8d7fSPeter Avalos fp = key_fingerprint(public, fptype, rep); 62218de8d7fSPeter Avalos ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART); 62318de8d7fSPeter Avalos printf("%u %s %s (%s)\n", key_size(public), fp, name, 62418de8d7fSPeter Avalos key_type(public)); 62518de8d7fSPeter Avalos if (log_level >= SYSLOG_LEVEL_VERBOSE) 62618de8d7fSPeter Avalos printf("%s\n", ra); 62718de8d7fSPeter Avalos xfree(ra); 62818de8d7fSPeter Avalos xfree(fp); 62918de8d7fSPeter Avalos } else { 63018de8d7fSPeter Avalos if (hash && (name = host_hash(name, NULL, 0)) == NULL) 63118de8d7fSPeter Avalos fatal("hash_host failed"); 63218de8d7fSPeter Avalos fprintf(f, "%s ", name); 63318de8d7fSPeter Avalos if (!key_write(public, f)) 63418de8d7fSPeter Avalos fatal("key_write failed"); 63518de8d7fSPeter Avalos fprintf(f, "\n"); 63618de8d7fSPeter Avalos } 63718de8d7fSPeter Avalos } 63818de8d7fSPeter Avalos 63918de8d7fSPeter Avalos static void 64018de8d7fSPeter Avalos do_known_hosts(struct passwd *pw, const char *name) 64118de8d7fSPeter Avalos { 64218de8d7fSPeter Avalos FILE *in, *out = stdout; 64318de8d7fSPeter Avalos Key *public; 64418de8d7fSPeter Avalos char *cp, *cp2, *kp, *kp2; 64518de8d7fSPeter Avalos char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN]; 64618de8d7fSPeter Avalos int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0; 64718de8d7fSPeter Avalos 64818de8d7fSPeter Avalos if (!have_identity) { 64918de8d7fSPeter Avalos cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid); 65018de8d7fSPeter Avalos if (strlcpy(identity_file, cp, sizeof(identity_file)) >= 65118de8d7fSPeter Avalos sizeof(identity_file)) 65218de8d7fSPeter Avalos fatal("Specified known hosts path too long"); 65318de8d7fSPeter Avalos xfree(cp); 65418de8d7fSPeter Avalos have_identity = 1; 65518de8d7fSPeter Avalos } 65618de8d7fSPeter Avalos if ((in = fopen(identity_file, "r")) == NULL) 65718de8d7fSPeter Avalos fatal("fopen: %s", strerror(errno)); 65818de8d7fSPeter Avalos 65918de8d7fSPeter Avalos /* 66018de8d7fSPeter Avalos * Find hosts goes to stdout, hash and deletions happen in-place 66118de8d7fSPeter Avalos * A corner case is ssh-keygen -HF foo, which should go to stdout 66218de8d7fSPeter Avalos */ 66318de8d7fSPeter Avalos if (!find_host && (hash_hosts || delete_host)) { 66418de8d7fSPeter Avalos if (strlcpy(tmp, identity_file, sizeof(tmp)) >= sizeof(tmp) || 66518de8d7fSPeter Avalos strlcat(tmp, ".XXXXXXXXXX", sizeof(tmp)) >= sizeof(tmp) || 66618de8d7fSPeter Avalos strlcpy(old, identity_file, sizeof(old)) >= sizeof(old) || 66718de8d7fSPeter Avalos strlcat(old, ".old", sizeof(old)) >= sizeof(old)) 66818de8d7fSPeter Avalos fatal("known_hosts path too long"); 66918de8d7fSPeter Avalos umask(077); 67018de8d7fSPeter Avalos if ((c = mkstemp(tmp)) == -1) 67118de8d7fSPeter Avalos fatal("mkstemp: %s", strerror(errno)); 67218de8d7fSPeter Avalos if ((out = fdopen(c, "w")) == NULL) { 67318de8d7fSPeter Avalos c = errno; 67418de8d7fSPeter Avalos unlink(tmp); 67518de8d7fSPeter Avalos fatal("fdopen: %s", strerror(c)); 67618de8d7fSPeter Avalos } 67718de8d7fSPeter Avalos inplace = 1; 67818de8d7fSPeter Avalos } 67918de8d7fSPeter Avalos 68018de8d7fSPeter Avalos while (fgets(line, sizeof(line), in)) { 68118de8d7fSPeter Avalos if ((cp = strchr(line, '\n')) == NULL) { 68218de8d7fSPeter Avalos error("line %d too long: %.40s...", num + 1, line); 68318de8d7fSPeter Avalos skip = 1; 68418de8d7fSPeter Avalos invalid = 1; 68518de8d7fSPeter Avalos continue; 68618de8d7fSPeter Avalos } 68718de8d7fSPeter Avalos num++; 68818de8d7fSPeter Avalos if (skip) { 68918de8d7fSPeter Avalos skip = 0; 69018de8d7fSPeter Avalos continue; 69118de8d7fSPeter Avalos } 69218de8d7fSPeter Avalos *cp = '\0'; 69318de8d7fSPeter Avalos 69418de8d7fSPeter Avalos /* Skip leading whitespace, empty and comment lines. */ 69518de8d7fSPeter Avalos for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 69618de8d7fSPeter Avalos ; 69718de8d7fSPeter Avalos if (!*cp || *cp == '\n' || *cp == '#') { 69818de8d7fSPeter Avalos if (inplace) 69918de8d7fSPeter Avalos fprintf(out, "%s\n", cp); 70018de8d7fSPeter Avalos continue; 70118de8d7fSPeter Avalos } 70218de8d7fSPeter Avalos /* Find the end of the host name portion. */ 70318de8d7fSPeter Avalos for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++) 70418de8d7fSPeter Avalos ; 70518de8d7fSPeter Avalos if (*kp == '\0' || *(kp + 1) == '\0') { 70618de8d7fSPeter Avalos error("line %d missing key: %.40s...", 70718de8d7fSPeter Avalos num, line); 70818de8d7fSPeter Avalos invalid = 1; 70918de8d7fSPeter Avalos continue; 71018de8d7fSPeter Avalos } 71118de8d7fSPeter Avalos *kp++ = '\0'; 71218de8d7fSPeter Avalos kp2 = kp; 71318de8d7fSPeter Avalos 71418de8d7fSPeter Avalos public = key_new(KEY_RSA1); 71518de8d7fSPeter Avalos if (key_read(public, &kp) != 1) { 71618de8d7fSPeter Avalos kp = kp2; 71718de8d7fSPeter Avalos key_free(public); 71818de8d7fSPeter Avalos public = key_new(KEY_UNSPEC); 71918de8d7fSPeter Avalos if (key_read(public, &kp) != 1) { 72018de8d7fSPeter Avalos error("line %d invalid key: %.40s...", 72118de8d7fSPeter Avalos num, line); 72218de8d7fSPeter Avalos key_free(public); 72318de8d7fSPeter Avalos invalid = 1; 72418de8d7fSPeter Avalos continue; 72518de8d7fSPeter Avalos } 72618de8d7fSPeter Avalos } 72718de8d7fSPeter Avalos 72818de8d7fSPeter Avalos if (*cp == HASH_DELIM) { 72918de8d7fSPeter Avalos if (find_host || delete_host) { 73018de8d7fSPeter Avalos cp2 = host_hash(name, cp, strlen(cp)); 73118de8d7fSPeter Avalos if (cp2 == NULL) { 73218de8d7fSPeter Avalos error("line %d: invalid hashed " 73318de8d7fSPeter Avalos "name: %.64s...", num, line); 73418de8d7fSPeter Avalos invalid = 1; 73518de8d7fSPeter Avalos continue; 73618de8d7fSPeter Avalos } 73718de8d7fSPeter Avalos c = (strcmp(cp2, cp) == 0); 73818de8d7fSPeter Avalos if (find_host && c) { 73918de8d7fSPeter Avalos printf("# Host %s found: " 74018de8d7fSPeter Avalos "line %d type %s\n", name, 74118de8d7fSPeter Avalos num, key_type(public)); 74218de8d7fSPeter Avalos print_host(out, cp, public, 0); 74318de8d7fSPeter Avalos } 74418de8d7fSPeter Avalos if (delete_host && !c) 74518de8d7fSPeter Avalos print_host(out, cp, public, 0); 74618de8d7fSPeter Avalos } else if (hash_hosts) 74718de8d7fSPeter Avalos print_host(out, cp, public, 0); 74818de8d7fSPeter Avalos } else { 74918de8d7fSPeter Avalos if (find_host || delete_host) { 75018de8d7fSPeter Avalos c = (match_hostname(name, cp, 75118de8d7fSPeter Avalos strlen(cp)) == 1); 75218de8d7fSPeter Avalos if (find_host && c) { 75318de8d7fSPeter Avalos printf("# Host %s found: " 75418de8d7fSPeter Avalos "line %d type %s\n", name, 75518de8d7fSPeter Avalos num, key_type(public)); 75618de8d7fSPeter Avalos print_host(out, name, public, 75718de8d7fSPeter Avalos hash_hosts); 75818de8d7fSPeter Avalos } 75918de8d7fSPeter Avalos if (delete_host && !c) 76018de8d7fSPeter Avalos print_host(out, cp, public, 0); 76118de8d7fSPeter Avalos } else if (hash_hosts) { 76218de8d7fSPeter Avalos for (cp2 = strsep(&cp, ","); 76318de8d7fSPeter Avalos cp2 != NULL && *cp2 != '\0'; 76418de8d7fSPeter Avalos cp2 = strsep(&cp, ",")) { 76518de8d7fSPeter Avalos if (strcspn(cp2, "*?!") != strlen(cp2)) 76618de8d7fSPeter Avalos fprintf(stderr, "Warning: " 76718de8d7fSPeter Avalos "ignoring host name with " 76818de8d7fSPeter Avalos "metacharacters: %.64s\n", 76918de8d7fSPeter Avalos cp2); 77018de8d7fSPeter Avalos else 77118de8d7fSPeter Avalos print_host(out, cp2, public, 1); 77218de8d7fSPeter Avalos } 77318de8d7fSPeter Avalos has_unhashed = 1; 77418de8d7fSPeter Avalos } 77518de8d7fSPeter Avalos } 77618de8d7fSPeter Avalos key_free(public); 77718de8d7fSPeter Avalos } 77818de8d7fSPeter Avalos fclose(in); 77918de8d7fSPeter Avalos 78018de8d7fSPeter Avalos if (invalid) { 78118de8d7fSPeter Avalos fprintf(stderr, "%s is not a valid known_hosts file.\n", 78218de8d7fSPeter Avalos identity_file); 78318de8d7fSPeter Avalos if (inplace) { 78418de8d7fSPeter Avalos fprintf(stderr, "Not replacing existing known_hosts " 78518de8d7fSPeter Avalos "file because of errors\n"); 78618de8d7fSPeter Avalos fclose(out); 78718de8d7fSPeter Avalos unlink(tmp); 78818de8d7fSPeter Avalos } 78918de8d7fSPeter Avalos exit(1); 79018de8d7fSPeter Avalos } 79118de8d7fSPeter Avalos 79218de8d7fSPeter Avalos if (inplace) { 79318de8d7fSPeter Avalos fclose(out); 79418de8d7fSPeter Avalos 79518de8d7fSPeter Avalos /* Backup existing file */ 79618de8d7fSPeter Avalos if (unlink(old) == -1 && errno != ENOENT) 79718de8d7fSPeter Avalos fatal("unlink %.100s: %s", old, strerror(errno)); 79818de8d7fSPeter Avalos if (link(identity_file, old) == -1) 79918de8d7fSPeter Avalos fatal("link %.100s to %.100s: %s", identity_file, old, 80018de8d7fSPeter Avalos strerror(errno)); 80118de8d7fSPeter Avalos /* Move new one into place */ 80218de8d7fSPeter Avalos if (rename(tmp, identity_file) == -1) { 80318de8d7fSPeter Avalos error("rename\"%s\" to \"%s\": %s", tmp, identity_file, 80418de8d7fSPeter Avalos strerror(errno)); 80518de8d7fSPeter Avalos unlink(tmp); 80618de8d7fSPeter Avalos unlink(old); 80718de8d7fSPeter Avalos exit(1); 80818de8d7fSPeter Avalos } 80918de8d7fSPeter Avalos 81018de8d7fSPeter Avalos fprintf(stderr, "%s updated.\n", identity_file); 81118de8d7fSPeter Avalos fprintf(stderr, "Original contents retained as %s\n", old); 81218de8d7fSPeter Avalos if (has_unhashed) { 81318de8d7fSPeter Avalos fprintf(stderr, "WARNING: %s contains unhashed " 81418de8d7fSPeter Avalos "entries\n", old); 81518de8d7fSPeter Avalos fprintf(stderr, "Delete this file to ensure privacy " 81618de8d7fSPeter Avalos "of hostnames\n"); 81718de8d7fSPeter Avalos } 81818de8d7fSPeter Avalos } 81918de8d7fSPeter Avalos 82018de8d7fSPeter Avalos exit(0); 82118de8d7fSPeter Avalos } 82218de8d7fSPeter Avalos 82318de8d7fSPeter Avalos /* 82418de8d7fSPeter Avalos * Perform changing a passphrase. The argument is the passwd structure 82518de8d7fSPeter Avalos * for the current user. 82618de8d7fSPeter Avalos */ 82718de8d7fSPeter Avalos static void 82818de8d7fSPeter Avalos do_change_passphrase(struct passwd *pw) 82918de8d7fSPeter Avalos { 83018de8d7fSPeter Avalos char *comment; 83118de8d7fSPeter Avalos char *old_passphrase, *passphrase1, *passphrase2; 83218de8d7fSPeter Avalos struct stat st; 83318de8d7fSPeter Avalos Key *private; 83418de8d7fSPeter Avalos 83518de8d7fSPeter Avalos if (!have_identity) 83618de8d7fSPeter Avalos ask_filename(pw, "Enter file in which the key is"); 83718de8d7fSPeter Avalos if (stat(identity_file, &st) < 0) { 83818de8d7fSPeter Avalos perror(identity_file); 83918de8d7fSPeter Avalos exit(1); 84018de8d7fSPeter Avalos } 84118de8d7fSPeter Avalos /* Try to load the file with empty passphrase. */ 84218de8d7fSPeter Avalos private = key_load_private(identity_file, "", &comment); 84318de8d7fSPeter Avalos if (private == NULL) { 84418de8d7fSPeter Avalos if (identity_passphrase) 84518de8d7fSPeter Avalos old_passphrase = xstrdup(identity_passphrase); 84618de8d7fSPeter Avalos else 84718de8d7fSPeter Avalos old_passphrase = 84818de8d7fSPeter Avalos read_passphrase("Enter old passphrase: ", 84918de8d7fSPeter Avalos RP_ALLOW_STDIN); 85018de8d7fSPeter Avalos private = key_load_private(identity_file, old_passphrase, 85118de8d7fSPeter Avalos &comment); 85218de8d7fSPeter Avalos memset(old_passphrase, 0, strlen(old_passphrase)); 85318de8d7fSPeter Avalos xfree(old_passphrase); 85418de8d7fSPeter Avalos if (private == NULL) { 85518de8d7fSPeter Avalos printf("Bad passphrase.\n"); 85618de8d7fSPeter Avalos exit(1); 85718de8d7fSPeter Avalos } 85818de8d7fSPeter Avalos } 85918de8d7fSPeter Avalos printf("Key has comment '%s'\n", comment); 86018de8d7fSPeter Avalos 86118de8d7fSPeter Avalos /* Ask the new passphrase (twice). */ 86218de8d7fSPeter Avalos if (identity_new_passphrase) { 86318de8d7fSPeter Avalos passphrase1 = xstrdup(identity_new_passphrase); 86418de8d7fSPeter Avalos passphrase2 = NULL; 86518de8d7fSPeter Avalos } else { 86618de8d7fSPeter Avalos passphrase1 = 86718de8d7fSPeter Avalos read_passphrase("Enter new passphrase (empty for no " 86818de8d7fSPeter Avalos "passphrase): ", RP_ALLOW_STDIN); 86918de8d7fSPeter Avalos passphrase2 = read_passphrase("Enter same passphrase again: ", 87018de8d7fSPeter Avalos RP_ALLOW_STDIN); 87118de8d7fSPeter Avalos 87218de8d7fSPeter Avalos /* Verify that they are the same. */ 87318de8d7fSPeter Avalos if (strcmp(passphrase1, passphrase2) != 0) { 87418de8d7fSPeter Avalos memset(passphrase1, 0, strlen(passphrase1)); 87518de8d7fSPeter Avalos memset(passphrase2, 0, strlen(passphrase2)); 87618de8d7fSPeter Avalos xfree(passphrase1); 87718de8d7fSPeter Avalos xfree(passphrase2); 87818de8d7fSPeter Avalos printf("Pass phrases do not match. Try again.\n"); 87918de8d7fSPeter Avalos exit(1); 88018de8d7fSPeter Avalos } 88118de8d7fSPeter Avalos /* Destroy the other copy. */ 88218de8d7fSPeter Avalos memset(passphrase2, 0, strlen(passphrase2)); 88318de8d7fSPeter Avalos xfree(passphrase2); 88418de8d7fSPeter Avalos } 88518de8d7fSPeter Avalos 88618de8d7fSPeter Avalos /* Save the file using the new passphrase. */ 88718de8d7fSPeter Avalos if (!key_save_private(private, identity_file, passphrase1, comment)) { 88818de8d7fSPeter Avalos printf("Saving the key failed: %s.\n", identity_file); 88918de8d7fSPeter Avalos memset(passphrase1, 0, strlen(passphrase1)); 89018de8d7fSPeter Avalos xfree(passphrase1); 89118de8d7fSPeter Avalos key_free(private); 89218de8d7fSPeter Avalos xfree(comment); 89318de8d7fSPeter Avalos exit(1); 89418de8d7fSPeter Avalos } 89518de8d7fSPeter Avalos /* Destroy the passphrase and the copy of the key in memory. */ 89618de8d7fSPeter Avalos memset(passphrase1, 0, strlen(passphrase1)); 89718de8d7fSPeter Avalos xfree(passphrase1); 89818de8d7fSPeter Avalos key_free(private); /* Destroys contents */ 89918de8d7fSPeter Avalos xfree(comment); 90018de8d7fSPeter Avalos 90118de8d7fSPeter Avalos printf("Your identification has been saved with the new passphrase.\n"); 90218de8d7fSPeter Avalos exit(0); 90318de8d7fSPeter Avalos } 90418de8d7fSPeter Avalos 90518de8d7fSPeter Avalos /* 90618de8d7fSPeter Avalos * Print the SSHFP RR. 90718de8d7fSPeter Avalos */ 90818de8d7fSPeter Avalos static int 90918de8d7fSPeter Avalos do_print_resource_record(struct passwd *pw, char *fname, char *hname) 91018de8d7fSPeter Avalos { 91118de8d7fSPeter Avalos Key *public; 91218de8d7fSPeter Avalos char *comment = NULL; 91318de8d7fSPeter Avalos struct stat st; 91418de8d7fSPeter Avalos 91518de8d7fSPeter Avalos if (fname == NULL) 91618de8d7fSPeter Avalos ask_filename(pw, "Enter file in which the key is"); 91718de8d7fSPeter Avalos if (stat(fname, &st) < 0) { 91818de8d7fSPeter Avalos if (errno == ENOENT) 91918de8d7fSPeter Avalos return 0; 92018de8d7fSPeter Avalos perror(fname); 92118de8d7fSPeter Avalos exit(1); 92218de8d7fSPeter Avalos } 92318de8d7fSPeter Avalos public = key_load_public(fname, &comment); 92418de8d7fSPeter Avalos if (public != NULL) { 92518de8d7fSPeter Avalos export_dns_rr(hname, public, stdout, print_generic); 92618de8d7fSPeter Avalos key_free(public); 92718de8d7fSPeter Avalos xfree(comment); 92818de8d7fSPeter Avalos return 1; 92918de8d7fSPeter Avalos } 93018de8d7fSPeter Avalos if (comment) 93118de8d7fSPeter Avalos xfree(comment); 93218de8d7fSPeter Avalos 93318de8d7fSPeter Avalos printf("failed to read v2 public key from %s.\n", fname); 93418de8d7fSPeter Avalos exit(1); 93518de8d7fSPeter Avalos } 93618de8d7fSPeter Avalos 93718de8d7fSPeter Avalos /* 93818de8d7fSPeter Avalos * Change the comment of a private key file. 93918de8d7fSPeter Avalos */ 94018de8d7fSPeter Avalos static void 94118de8d7fSPeter Avalos do_change_comment(struct passwd *pw) 94218de8d7fSPeter Avalos { 94318de8d7fSPeter Avalos char new_comment[1024], *comment, *passphrase; 94418de8d7fSPeter Avalos Key *private; 94518de8d7fSPeter Avalos Key *public; 94618de8d7fSPeter Avalos struct stat st; 94718de8d7fSPeter Avalos FILE *f; 94818de8d7fSPeter Avalos int fd; 94918de8d7fSPeter Avalos 95018de8d7fSPeter Avalos if (!have_identity) 95118de8d7fSPeter Avalos ask_filename(pw, "Enter file in which the key is"); 95218de8d7fSPeter Avalos if (stat(identity_file, &st) < 0) { 95318de8d7fSPeter Avalos perror(identity_file); 95418de8d7fSPeter Avalos exit(1); 95518de8d7fSPeter Avalos } 95618de8d7fSPeter Avalos private = key_load_private(identity_file, "", &comment); 95718de8d7fSPeter Avalos if (private == NULL) { 95818de8d7fSPeter Avalos if (identity_passphrase) 95918de8d7fSPeter Avalos passphrase = xstrdup(identity_passphrase); 96018de8d7fSPeter Avalos else if (identity_new_passphrase) 96118de8d7fSPeter Avalos passphrase = xstrdup(identity_new_passphrase); 96218de8d7fSPeter Avalos else 96318de8d7fSPeter Avalos passphrase = read_passphrase("Enter passphrase: ", 96418de8d7fSPeter Avalos RP_ALLOW_STDIN); 96518de8d7fSPeter Avalos /* Try to load using the passphrase. */ 96618de8d7fSPeter Avalos private = key_load_private(identity_file, passphrase, &comment); 96718de8d7fSPeter Avalos if (private == NULL) { 96818de8d7fSPeter Avalos memset(passphrase, 0, strlen(passphrase)); 96918de8d7fSPeter Avalos xfree(passphrase); 97018de8d7fSPeter Avalos printf("Bad passphrase.\n"); 97118de8d7fSPeter Avalos exit(1); 97218de8d7fSPeter Avalos } 97318de8d7fSPeter Avalos } else { 97418de8d7fSPeter Avalos passphrase = xstrdup(""); 97518de8d7fSPeter Avalos } 97618de8d7fSPeter Avalos if (private->type != KEY_RSA1) { 97718de8d7fSPeter Avalos fprintf(stderr, "Comments are only supported for RSA1 keys.\n"); 97818de8d7fSPeter Avalos key_free(private); 97918de8d7fSPeter Avalos exit(1); 98018de8d7fSPeter Avalos } 98118de8d7fSPeter Avalos printf("Key now has comment '%s'\n", comment); 98218de8d7fSPeter Avalos 98318de8d7fSPeter Avalos if (identity_comment) { 98418de8d7fSPeter Avalos strlcpy(new_comment, identity_comment, sizeof(new_comment)); 98518de8d7fSPeter Avalos } else { 98618de8d7fSPeter Avalos printf("Enter new comment: "); 98718de8d7fSPeter Avalos fflush(stdout); 98818de8d7fSPeter Avalos if (!fgets(new_comment, sizeof(new_comment), stdin)) { 98918de8d7fSPeter Avalos memset(passphrase, 0, strlen(passphrase)); 99018de8d7fSPeter Avalos key_free(private); 99118de8d7fSPeter Avalos exit(1); 99218de8d7fSPeter Avalos } 99318de8d7fSPeter Avalos new_comment[strcspn(new_comment, "\n")] = '\0'; 99418de8d7fSPeter Avalos } 99518de8d7fSPeter Avalos 99618de8d7fSPeter Avalos /* Save the file using the new passphrase. */ 99718de8d7fSPeter Avalos if (!key_save_private(private, identity_file, passphrase, new_comment)) { 99818de8d7fSPeter Avalos printf("Saving the key failed: %s.\n", identity_file); 99918de8d7fSPeter Avalos memset(passphrase, 0, strlen(passphrase)); 100018de8d7fSPeter Avalos xfree(passphrase); 100118de8d7fSPeter Avalos key_free(private); 100218de8d7fSPeter Avalos xfree(comment); 100318de8d7fSPeter Avalos exit(1); 100418de8d7fSPeter Avalos } 100518de8d7fSPeter Avalos memset(passphrase, 0, strlen(passphrase)); 100618de8d7fSPeter Avalos xfree(passphrase); 100718de8d7fSPeter Avalos public = key_from_private(private); 100818de8d7fSPeter Avalos key_free(private); 100918de8d7fSPeter Avalos 101018de8d7fSPeter Avalos strlcat(identity_file, ".pub", sizeof(identity_file)); 101118de8d7fSPeter Avalos fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); 101218de8d7fSPeter Avalos if (fd == -1) { 101318de8d7fSPeter Avalos printf("Could not save your public key in %s\n", identity_file); 101418de8d7fSPeter Avalos exit(1); 101518de8d7fSPeter Avalos } 101618de8d7fSPeter Avalos f = fdopen(fd, "w"); 101718de8d7fSPeter Avalos if (f == NULL) { 1018*cb5eb4f1SPeter Avalos printf("fdopen %s failed\n", identity_file); 101918de8d7fSPeter Avalos exit(1); 102018de8d7fSPeter Avalos } 102118de8d7fSPeter Avalos if (!key_write(public, f)) 1022*cb5eb4f1SPeter Avalos fprintf(stderr, "write key failed\n"); 102318de8d7fSPeter Avalos key_free(public); 102418de8d7fSPeter Avalos fprintf(f, " %s\n", new_comment); 102518de8d7fSPeter Avalos fclose(f); 102618de8d7fSPeter Avalos 102718de8d7fSPeter Avalos xfree(comment); 102818de8d7fSPeter Avalos 102918de8d7fSPeter Avalos printf("The comment in your key file has been changed.\n"); 103018de8d7fSPeter Avalos exit(0); 103118de8d7fSPeter Avalos } 103218de8d7fSPeter Avalos 103318de8d7fSPeter Avalos static void 103418de8d7fSPeter Avalos usage(void) 103518de8d7fSPeter Avalos { 103618de8d7fSPeter Avalos fprintf(stderr, "usage: %s [options]\n", __progname); 103718de8d7fSPeter Avalos fprintf(stderr, "Options:\n"); 103818de8d7fSPeter Avalos fprintf(stderr, " -a trials Number of trials for screening DH-GEX moduli.\n"); 103918de8d7fSPeter Avalos fprintf(stderr, " -B Show bubblebabble digest of key file.\n"); 104018de8d7fSPeter Avalos fprintf(stderr, " -b bits Number of bits in the key to create.\n"); 104118de8d7fSPeter Avalos fprintf(stderr, " -C comment Provide new comment.\n"); 104218de8d7fSPeter Avalos fprintf(stderr, " -c Change comment in private and public key files.\n"); 104318de8d7fSPeter Avalos #ifdef SMARTCARD 104418de8d7fSPeter Avalos fprintf(stderr, " -D reader Download public key from smartcard.\n"); 104518de8d7fSPeter Avalos #endif /* SMARTCARD */ 104618de8d7fSPeter Avalos fprintf(stderr, " -e Convert OpenSSH to RFC 4716 key file.\n"); 104718de8d7fSPeter Avalos fprintf(stderr, " -F hostname Find hostname in known hosts file.\n"); 104818de8d7fSPeter Avalos fprintf(stderr, " -f filename Filename of the key file.\n"); 104918de8d7fSPeter Avalos fprintf(stderr, " -G file Generate candidates for DH-GEX moduli.\n"); 105018de8d7fSPeter Avalos fprintf(stderr, " -g Use generic DNS resource record format.\n"); 105118de8d7fSPeter Avalos fprintf(stderr, " -H Hash names in known_hosts file.\n"); 105218de8d7fSPeter Avalos fprintf(stderr, " -i Convert RFC 4716 to OpenSSH key file.\n"); 105318de8d7fSPeter Avalos fprintf(stderr, " -l Show fingerprint of key file.\n"); 105418de8d7fSPeter Avalos fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n"); 105518de8d7fSPeter Avalos fprintf(stderr, " -N phrase Provide new passphrase.\n"); 105618de8d7fSPeter Avalos fprintf(stderr, " -P phrase Provide old passphrase.\n"); 105718de8d7fSPeter Avalos fprintf(stderr, " -p Change passphrase of private key file.\n"); 105818de8d7fSPeter Avalos fprintf(stderr, " -q Quiet.\n"); 105918de8d7fSPeter Avalos fprintf(stderr, " -R hostname Remove host from known_hosts file.\n"); 106018de8d7fSPeter Avalos fprintf(stderr, " -r hostname Print DNS resource record.\n"); 106118de8d7fSPeter Avalos fprintf(stderr, " -S start Start point (hex) for generating DH-GEX moduli.\n"); 106218de8d7fSPeter Avalos fprintf(stderr, " -T file Screen candidates for DH-GEX moduli.\n"); 106318de8d7fSPeter Avalos fprintf(stderr, " -t type Specify type of key to create.\n"); 106418de8d7fSPeter Avalos #ifdef SMARTCARD 106518de8d7fSPeter Avalos fprintf(stderr, " -U reader Upload private key to smartcard.\n"); 106618de8d7fSPeter Avalos #endif /* SMARTCARD */ 106718de8d7fSPeter Avalos fprintf(stderr, " -v Verbose.\n"); 106818de8d7fSPeter Avalos fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n"); 106918de8d7fSPeter Avalos fprintf(stderr, " -y Read private key file and print public key.\n"); 107018de8d7fSPeter Avalos 107118de8d7fSPeter Avalos exit(1); 107218de8d7fSPeter Avalos } 107318de8d7fSPeter Avalos 107418de8d7fSPeter Avalos /* 107518de8d7fSPeter Avalos * Main program for key management. 107618de8d7fSPeter Avalos */ 107718de8d7fSPeter Avalos int 107818de8d7fSPeter Avalos main(int argc, char **argv) 107918de8d7fSPeter Avalos { 108018de8d7fSPeter Avalos char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; 108118de8d7fSPeter Avalos char out_file[MAXPATHLEN], *reader_id = NULL; 108218de8d7fSPeter Avalos char *rr_hostname = NULL; 108318de8d7fSPeter Avalos Key *private, *public; 108418de8d7fSPeter Avalos struct passwd *pw; 108518de8d7fSPeter Avalos struct stat st; 108618de8d7fSPeter Avalos int opt, type, fd, download = 0; 108718de8d7fSPeter Avalos u_int32_t memory = 0, generator_wanted = 0, trials = 100; 108818de8d7fSPeter Avalos int do_gen_candidates = 0, do_screen_candidates = 0; 108918de8d7fSPeter Avalos BIGNUM *start = NULL; 109018de8d7fSPeter Avalos FILE *f; 109118de8d7fSPeter Avalos const char *errstr; 109218de8d7fSPeter Avalos 109318de8d7fSPeter Avalos extern int optind; 109418de8d7fSPeter Avalos extern char *optarg; 109518de8d7fSPeter Avalos 109618de8d7fSPeter Avalos /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 109718de8d7fSPeter Avalos sanitise_stdfd(); 109818de8d7fSPeter Avalos 109918de8d7fSPeter Avalos __progname = ssh_get_progname(argv[0]); 110018de8d7fSPeter Avalos 110118de8d7fSPeter Avalos SSLeay_add_all_algorithms(); 110218de8d7fSPeter Avalos log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1); 110318de8d7fSPeter Avalos 110418de8d7fSPeter Avalos init_rng(); 110518de8d7fSPeter Avalos seed_rng(); 110618de8d7fSPeter Avalos 110718de8d7fSPeter Avalos /* we need this for the home * directory. */ 110818de8d7fSPeter Avalos pw = getpwuid(getuid()); 110918de8d7fSPeter Avalos if (!pw) { 111018de8d7fSPeter Avalos printf("You don't exist, go away!\n"); 111118de8d7fSPeter Avalos exit(1); 111218de8d7fSPeter Avalos } 111318de8d7fSPeter Avalos if (gethostname(hostname, sizeof(hostname)) < 0) { 111418de8d7fSPeter Avalos perror("gethostname"); 111518de8d7fSPeter Avalos exit(1); 111618de8d7fSPeter Avalos } 111718de8d7fSPeter Avalos 111818de8d7fSPeter Avalos while ((opt = getopt(argc, argv, 111918de8d7fSPeter Avalos "degiqpclBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) { 112018de8d7fSPeter Avalos switch (opt) { 112118de8d7fSPeter Avalos case 'b': 112218de8d7fSPeter Avalos bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr); 112318de8d7fSPeter Avalos if (errstr) 112418de8d7fSPeter Avalos fatal("Bits has bad value %s (%s)", 112518de8d7fSPeter Avalos optarg, errstr); 112618de8d7fSPeter Avalos break; 112718de8d7fSPeter Avalos case 'F': 112818de8d7fSPeter Avalos find_host = 1; 112918de8d7fSPeter Avalos rr_hostname = optarg; 113018de8d7fSPeter Avalos break; 113118de8d7fSPeter Avalos case 'H': 113218de8d7fSPeter Avalos hash_hosts = 1; 113318de8d7fSPeter Avalos break; 113418de8d7fSPeter Avalos case 'R': 113518de8d7fSPeter Avalos delete_host = 1; 113618de8d7fSPeter Avalos rr_hostname = optarg; 113718de8d7fSPeter Avalos break; 113818de8d7fSPeter Avalos case 'l': 113918de8d7fSPeter Avalos print_fingerprint = 1; 114018de8d7fSPeter Avalos break; 114118de8d7fSPeter Avalos case 'B': 114218de8d7fSPeter Avalos print_bubblebabble = 1; 114318de8d7fSPeter Avalos break; 114418de8d7fSPeter Avalos case 'p': 114518de8d7fSPeter Avalos change_passphrase = 1; 114618de8d7fSPeter Avalos break; 114718de8d7fSPeter Avalos case 'c': 114818de8d7fSPeter Avalos change_comment = 1; 114918de8d7fSPeter Avalos break; 115018de8d7fSPeter Avalos case 'f': 115118de8d7fSPeter Avalos if (strlcpy(identity_file, optarg, sizeof(identity_file)) >= 115218de8d7fSPeter Avalos sizeof(identity_file)) 115318de8d7fSPeter Avalos fatal("Identity filename too long"); 115418de8d7fSPeter Avalos have_identity = 1; 115518de8d7fSPeter Avalos break; 115618de8d7fSPeter Avalos case 'g': 115718de8d7fSPeter Avalos print_generic = 1; 115818de8d7fSPeter Avalos break; 115918de8d7fSPeter Avalos case 'P': 116018de8d7fSPeter Avalos identity_passphrase = optarg; 116118de8d7fSPeter Avalos break; 116218de8d7fSPeter Avalos case 'N': 116318de8d7fSPeter Avalos identity_new_passphrase = optarg; 116418de8d7fSPeter Avalos break; 116518de8d7fSPeter Avalos case 'C': 116618de8d7fSPeter Avalos identity_comment = optarg; 116718de8d7fSPeter Avalos break; 116818de8d7fSPeter Avalos case 'q': 116918de8d7fSPeter Avalos quiet = 1; 117018de8d7fSPeter Avalos break; 117118de8d7fSPeter Avalos case 'e': 117218de8d7fSPeter Avalos case 'x': 117318de8d7fSPeter Avalos /* export key */ 117418de8d7fSPeter Avalos convert_to_ssh2 = 1; 117518de8d7fSPeter Avalos break; 117618de8d7fSPeter Avalos case 'i': 117718de8d7fSPeter Avalos case 'X': 117818de8d7fSPeter Avalos /* import key */ 117918de8d7fSPeter Avalos convert_from_ssh2 = 1; 118018de8d7fSPeter Avalos break; 118118de8d7fSPeter Avalos case 'y': 118218de8d7fSPeter Avalos print_public = 1; 118318de8d7fSPeter Avalos break; 118418de8d7fSPeter Avalos case 'd': 118518de8d7fSPeter Avalos key_type_name = "dsa"; 118618de8d7fSPeter Avalos break; 118718de8d7fSPeter Avalos case 't': 118818de8d7fSPeter Avalos key_type_name = optarg; 118918de8d7fSPeter Avalos break; 119018de8d7fSPeter Avalos case 'D': 119118de8d7fSPeter Avalos download = 1; 119218de8d7fSPeter Avalos /*FALLTHROUGH*/ 119318de8d7fSPeter Avalos case 'U': 119418de8d7fSPeter Avalos reader_id = optarg; 119518de8d7fSPeter Avalos break; 119618de8d7fSPeter Avalos case 'v': 119718de8d7fSPeter Avalos if (log_level == SYSLOG_LEVEL_INFO) 119818de8d7fSPeter Avalos log_level = SYSLOG_LEVEL_DEBUG1; 119918de8d7fSPeter Avalos else { 120018de8d7fSPeter Avalos if (log_level >= SYSLOG_LEVEL_DEBUG1 && 120118de8d7fSPeter Avalos log_level < SYSLOG_LEVEL_DEBUG3) 120218de8d7fSPeter Avalos log_level++; 120318de8d7fSPeter Avalos } 120418de8d7fSPeter Avalos break; 120518de8d7fSPeter Avalos case 'r': 120618de8d7fSPeter Avalos rr_hostname = optarg; 120718de8d7fSPeter Avalos break; 120818de8d7fSPeter Avalos case 'W': 120918de8d7fSPeter Avalos generator_wanted = (u_int32_t)strtonum(optarg, 1, 121018de8d7fSPeter Avalos UINT_MAX, &errstr); 121118de8d7fSPeter Avalos if (errstr) 121218de8d7fSPeter Avalos fatal("Desired generator has bad value: %s (%s)", 121318de8d7fSPeter Avalos optarg, errstr); 121418de8d7fSPeter Avalos break; 121518de8d7fSPeter Avalos case 'a': 121618de8d7fSPeter Avalos trials = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr); 121718de8d7fSPeter Avalos if (errstr) 121818de8d7fSPeter Avalos fatal("Invalid number of trials: %s (%s)", 121918de8d7fSPeter Avalos optarg, errstr); 122018de8d7fSPeter Avalos break; 122118de8d7fSPeter Avalos case 'M': 122218de8d7fSPeter Avalos memory = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr); 122318de8d7fSPeter Avalos if (errstr) { 122418de8d7fSPeter Avalos fatal("Memory limit is %s: %s", errstr, optarg); 122518de8d7fSPeter Avalos } 122618de8d7fSPeter Avalos break; 122718de8d7fSPeter Avalos case 'G': 122818de8d7fSPeter Avalos do_gen_candidates = 1; 122918de8d7fSPeter Avalos if (strlcpy(out_file, optarg, sizeof(out_file)) >= 123018de8d7fSPeter Avalos sizeof(out_file)) 123118de8d7fSPeter Avalos fatal("Output filename too long"); 123218de8d7fSPeter Avalos break; 123318de8d7fSPeter Avalos case 'T': 123418de8d7fSPeter Avalos do_screen_candidates = 1; 123518de8d7fSPeter Avalos if (strlcpy(out_file, optarg, sizeof(out_file)) >= 123618de8d7fSPeter Avalos sizeof(out_file)) 123718de8d7fSPeter Avalos fatal("Output filename too long"); 123818de8d7fSPeter Avalos break; 123918de8d7fSPeter Avalos case 'S': 124018de8d7fSPeter Avalos /* XXX - also compare length against bits */ 124118de8d7fSPeter Avalos if (BN_hex2bn(&start, optarg) == 0) 124218de8d7fSPeter Avalos fatal("Invalid start point."); 124318de8d7fSPeter Avalos break; 124418de8d7fSPeter Avalos case '?': 124518de8d7fSPeter Avalos default: 124618de8d7fSPeter Avalos usage(); 124718de8d7fSPeter Avalos } 124818de8d7fSPeter Avalos } 124918de8d7fSPeter Avalos 125018de8d7fSPeter Avalos /* reinit */ 125118de8d7fSPeter Avalos log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1); 125218de8d7fSPeter Avalos 125318de8d7fSPeter Avalos if (optind < argc) { 125418de8d7fSPeter Avalos printf("Too many arguments.\n"); 125518de8d7fSPeter Avalos usage(); 125618de8d7fSPeter Avalos } 125718de8d7fSPeter Avalos if (change_passphrase && change_comment) { 125818de8d7fSPeter Avalos printf("Can only have one of -p and -c.\n"); 125918de8d7fSPeter Avalos usage(); 126018de8d7fSPeter Avalos } 126118de8d7fSPeter Avalos if (print_fingerprint && (delete_host || hash_hosts)) { 126218de8d7fSPeter Avalos printf("Cannot use -l with -D or -R.\n"); 126318de8d7fSPeter Avalos usage(); 126418de8d7fSPeter Avalos } 126518de8d7fSPeter Avalos if (delete_host || hash_hosts || find_host) 126618de8d7fSPeter Avalos do_known_hosts(pw, rr_hostname); 126718de8d7fSPeter Avalos if (print_fingerprint || print_bubblebabble) 126818de8d7fSPeter Avalos do_fingerprint(pw); 126918de8d7fSPeter Avalos if (change_passphrase) 127018de8d7fSPeter Avalos do_change_passphrase(pw); 127118de8d7fSPeter Avalos if (change_comment) 127218de8d7fSPeter Avalos do_change_comment(pw); 127318de8d7fSPeter Avalos if (convert_to_ssh2) 127418de8d7fSPeter Avalos do_convert_to_ssh2(pw); 127518de8d7fSPeter Avalos if (convert_from_ssh2) 127618de8d7fSPeter Avalos do_convert_from_ssh2(pw); 127718de8d7fSPeter Avalos if (print_public) 127818de8d7fSPeter Avalos do_print_public(pw); 127918de8d7fSPeter Avalos if (rr_hostname != NULL) { 128018de8d7fSPeter Avalos unsigned int n = 0; 128118de8d7fSPeter Avalos 128218de8d7fSPeter Avalos if (have_identity) { 128318de8d7fSPeter Avalos n = do_print_resource_record(pw, 128418de8d7fSPeter Avalos identity_file, rr_hostname); 128518de8d7fSPeter Avalos if (n == 0) { 128618de8d7fSPeter Avalos perror(identity_file); 128718de8d7fSPeter Avalos exit(1); 128818de8d7fSPeter Avalos } 128918de8d7fSPeter Avalos exit(0); 129018de8d7fSPeter Avalos } else { 129118de8d7fSPeter Avalos 129218de8d7fSPeter Avalos n += do_print_resource_record(pw, 129318de8d7fSPeter Avalos _PATH_HOST_RSA_KEY_FILE, rr_hostname); 129418de8d7fSPeter Avalos n += do_print_resource_record(pw, 129518de8d7fSPeter Avalos _PATH_HOST_DSA_KEY_FILE, rr_hostname); 129618de8d7fSPeter Avalos 129718de8d7fSPeter Avalos if (n == 0) 129818de8d7fSPeter Avalos fatal("no keys found."); 129918de8d7fSPeter Avalos exit(0); 130018de8d7fSPeter Avalos } 130118de8d7fSPeter Avalos } 130218de8d7fSPeter Avalos if (reader_id != NULL) { 130318de8d7fSPeter Avalos #ifdef SMARTCARD 130418de8d7fSPeter Avalos if (download) 130518de8d7fSPeter Avalos do_download(pw, reader_id); 130618de8d7fSPeter Avalos else 130718de8d7fSPeter Avalos do_upload(pw, reader_id); 130818de8d7fSPeter Avalos #else /* SMARTCARD */ 130918de8d7fSPeter Avalos fatal("no support for smartcards."); 131018de8d7fSPeter Avalos #endif /* SMARTCARD */ 131118de8d7fSPeter Avalos } 131218de8d7fSPeter Avalos 131318de8d7fSPeter Avalos if (do_gen_candidates) { 131418de8d7fSPeter Avalos FILE *out = fopen(out_file, "w"); 131518de8d7fSPeter Avalos 131618de8d7fSPeter Avalos if (out == NULL) { 131718de8d7fSPeter Avalos error("Couldn't open modulus candidate file \"%s\": %s", 131818de8d7fSPeter Avalos out_file, strerror(errno)); 131918de8d7fSPeter Avalos return (1); 132018de8d7fSPeter Avalos } 132118de8d7fSPeter Avalos if (bits == 0) 132218de8d7fSPeter Avalos bits = DEFAULT_BITS; 132318de8d7fSPeter Avalos if (gen_candidates(out, memory, bits, start) != 0) 132418de8d7fSPeter Avalos fatal("modulus candidate generation failed"); 132518de8d7fSPeter Avalos 132618de8d7fSPeter Avalos return (0); 132718de8d7fSPeter Avalos } 132818de8d7fSPeter Avalos 132918de8d7fSPeter Avalos if (do_screen_candidates) { 133018de8d7fSPeter Avalos FILE *in; 133118de8d7fSPeter Avalos FILE *out = fopen(out_file, "w"); 133218de8d7fSPeter Avalos 133318de8d7fSPeter Avalos if (have_identity && strcmp(identity_file, "-") != 0) { 133418de8d7fSPeter Avalos if ((in = fopen(identity_file, "r")) == NULL) { 133518de8d7fSPeter Avalos fatal("Couldn't open modulus candidate " 133618de8d7fSPeter Avalos "file \"%s\": %s", identity_file, 133718de8d7fSPeter Avalos strerror(errno)); 133818de8d7fSPeter Avalos } 133918de8d7fSPeter Avalos } else 134018de8d7fSPeter Avalos in = stdin; 134118de8d7fSPeter Avalos 134218de8d7fSPeter Avalos if (out == NULL) { 134318de8d7fSPeter Avalos fatal("Couldn't open moduli file \"%s\": %s", 134418de8d7fSPeter Avalos out_file, strerror(errno)); 134518de8d7fSPeter Avalos } 134618de8d7fSPeter Avalos if (prime_test(in, out, trials, generator_wanted) != 0) 134718de8d7fSPeter Avalos fatal("modulus screening failed"); 134818de8d7fSPeter Avalos return (0); 134918de8d7fSPeter Avalos } 135018de8d7fSPeter Avalos 135118de8d7fSPeter Avalos arc4random_stir(); 135218de8d7fSPeter Avalos 135318de8d7fSPeter Avalos if (key_type_name == NULL) 135418de8d7fSPeter Avalos key_type_name = "rsa"; 135518de8d7fSPeter Avalos 135618de8d7fSPeter Avalos type = key_type_from_name(key_type_name); 135718de8d7fSPeter Avalos if (type == KEY_UNSPEC) { 135818de8d7fSPeter Avalos fprintf(stderr, "unknown key type %s\n", key_type_name); 135918de8d7fSPeter Avalos exit(1); 136018de8d7fSPeter Avalos } 136118de8d7fSPeter Avalos if (bits == 0) 136218de8d7fSPeter Avalos bits = (type == KEY_DSA) ? DEFAULT_BITS_DSA : DEFAULT_BITS; 136318de8d7fSPeter Avalos if (type == KEY_DSA && bits != 1024) 136418de8d7fSPeter Avalos fatal("DSA keys must be 1024 bits"); 136518de8d7fSPeter Avalos if (!quiet) 136618de8d7fSPeter Avalos printf("Generating public/private %s key pair.\n", key_type_name); 136718de8d7fSPeter Avalos private = key_generate(type, bits); 136818de8d7fSPeter Avalos if (private == NULL) { 1369*cb5eb4f1SPeter Avalos fprintf(stderr, "key_generate failed\n"); 137018de8d7fSPeter Avalos exit(1); 137118de8d7fSPeter Avalos } 137218de8d7fSPeter Avalos public = key_from_private(private); 137318de8d7fSPeter Avalos 137418de8d7fSPeter Avalos if (!have_identity) 137518de8d7fSPeter Avalos ask_filename(pw, "Enter file in which to save the key"); 137618de8d7fSPeter Avalos 137718de8d7fSPeter Avalos /* Create ~/.ssh directory if it doesn't already exist. */ 137818de8d7fSPeter Avalos snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR); 137918de8d7fSPeter Avalos if (strstr(identity_file, dotsshdir) != NULL && 138018de8d7fSPeter Avalos stat(dotsshdir, &st) < 0) { 138118de8d7fSPeter Avalos if (mkdir(dotsshdir, 0700) < 0) 138218de8d7fSPeter Avalos error("Could not create directory '%s'.", dotsshdir); 138318de8d7fSPeter Avalos else if (!quiet) 138418de8d7fSPeter Avalos printf("Created directory '%s'.\n", dotsshdir); 138518de8d7fSPeter Avalos } 138618de8d7fSPeter Avalos /* If the file already exists, ask the user to confirm. */ 138718de8d7fSPeter Avalos if (stat(identity_file, &st) >= 0) { 138818de8d7fSPeter Avalos char yesno[3]; 138918de8d7fSPeter Avalos printf("%s already exists.\n", identity_file); 139018de8d7fSPeter Avalos printf("Overwrite (y/n)? "); 139118de8d7fSPeter Avalos fflush(stdout); 139218de8d7fSPeter Avalos if (fgets(yesno, sizeof(yesno), stdin) == NULL) 139318de8d7fSPeter Avalos exit(1); 139418de8d7fSPeter Avalos if (yesno[0] != 'y' && yesno[0] != 'Y') 139518de8d7fSPeter Avalos exit(1); 139618de8d7fSPeter Avalos } 139718de8d7fSPeter Avalos /* Ask for a passphrase (twice). */ 139818de8d7fSPeter Avalos if (identity_passphrase) 139918de8d7fSPeter Avalos passphrase1 = xstrdup(identity_passphrase); 140018de8d7fSPeter Avalos else if (identity_new_passphrase) 140118de8d7fSPeter Avalos passphrase1 = xstrdup(identity_new_passphrase); 140218de8d7fSPeter Avalos else { 140318de8d7fSPeter Avalos passphrase_again: 140418de8d7fSPeter Avalos passphrase1 = 140518de8d7fSPeter Avalos read_passphrase("Enter passphrase (empty for no " 140618de8d7fSPeter Avalos "passphrase): ", RP_ALLOW_STDIN); 140718de8d7fSPeter Avalos passphrase2 = read_passphrase("Enter same passphrase again: ", 140818de8d7fSPeter Avalos RP_ALLOW_STDIN); 140918de8d7fSPeter Avalos if (strcmp(passphrase1, passphrase2) != 0) { 141018de8d7fSPeter Avalos /* 141118de8d7fSPeter Avalos * The passphrases do not match. Clear them and 141218de8d7fSPeter Avalos * retry. 141318de8d7fSPeter Avalos */ 141418de8d7fSPeter Avalos memset(passphrase1, 0, strlen(passphrase1)); 141518de8d7fSPeter Avalos memset(passphrase2, 0, strlen(passphrase2)); 141618de8d7fSPeter Avalos xfree(passphrase1); 141718de8d7fSPeter Avalos xfree(passphrase2); 141818de8d7fSPeter Avalos printf("Passphrases do not match. Try again.\n"); 141918de8d7fSPeter Avalos goto passphrase_again; 142018de8d7fSPeter Avalos } 142118de8d7fSPeter Avalos /* Clear the other copy of the passphrase. */ 142218de8d7fSPeter Avalos memset(passphrase2, 0, strlen(passphrase2)); 142318de8d7fSPeter Avalos xfree(passphrase2); 142418de8d7fSPeter Avalos } 142518de8d7fSPeter Avalos 142618de8d7fSPeter Avalos if (identity_comment) { 142718de8d7fSPeter Avalos strlcpy(comment, identity_comment, sizeof(comment)); 142818de8d7fSPeter Avalos } else { 1429*cb5eb4f1SPeter Avalos /* Create default comment field for the passphrase. */ 143018de8d7fSPeter Avalos snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); 143118de8d7fSPeter Avalos } 143218de8d7fSPeter Avalos 143318de8d7fSPeter Avalos /* Save the key with the given passphrase and comment. */ 143418de8d7fSPeter Avalos if (!key_save_private(private, identity_file, passphrase1, comment)) { 143518de8d7fSPeter Avalos printf("Saving the key failed: %s.\n", identity_file); 143618de8d7fSPeter Avalos memset(passphrase1, 0, strlen(passphrase1)); 143718de8d7fSPeter Avalos xfree(passphrase1); 143818de8d7fSPeter Avalos exit(1); 143918de8d7fSPeter Avalos } 144018de8d7fSPeter Avalos /* Clear the passphrase. */ 144118de8d7fSPeter Avalos memset(passphrase1, 0, strlen(passphrase1)); 144218de8d7fSPeter Avalos xfree(passphrase1); 144318de8d7fSPeter Avalos 144418de8d7fSPeter Avalos /* Clear the private key and the random number generator. */ 144518de8d7fSPeter Avalos key_free(private); 144618de8d7fSPeter Avalos arc4random_stir(); 144718de8d7fSPeter Avalos 144818de8d7fSPeter Avalos if (!quiet) 144918de8d7fSPeter Avalos printf("Your identification has been saved in %s.\n", identity_file); 145018de8d7fSPeter Avalos 145118de8d7fSPeter Avalos strlcat(identity_file, ".pub", sizeof(identity_file)); 145218de8d7fSPeter Avalos fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); 145318de8d7fSPeter Avalos if (fd == -1) { 145418de8d7fSPeter Avalos printf("Could not save your public key in %s\n", identity_file); 145518de8d7fSPeter Avalos exit(1); 145618de8d7fSPeter Avalos } 145718de8d7fSPeter Avalos f = fdopen(fd, "w"); 145818de8d7fSPeter Avalos if (f == NULL) { 1459*cb5eb4f1SPeter Avalos printf("fdopen %s failed\n", identity_file); 146018de8d7fSPeter Avalos exit(1); 146118de8d7fSPeter Avalos } 146218de8d7fSPeter Avalos if (!key_write(public, f)) 1463*cb5eb4f1SPeter Avalos fprintf(stderr, "write key failed\n"); 146418de8d7fSPeter Avalos fprintf(f, " %s\n", comment); 146518de8d7fSPeter Avalos fclose(f); 146618de8d7fSPeter Avalos 146718de8d7fSPeter Avalos if (!quiet) { 146818de8d7fSPeter Avalos char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX); 146918de8d7fSPeter Avalos char *ra = key_fingerprint(public, SSH_FP_MD5, 147018de8d7fSPeter Avalos SSH_FP_RANDOMART); 147118de8d7fSPeter Avalos printf("Your public key has been saved in %s.\n", 147218de8d7fSPeter Avalos identity_file); 147318de8d7fSPeter Avalos printf("The key fingerprint is:\n"); 147418de8d7fSPeter Avalos printf("%s %s\n", fp, comment); 147518de8d7fSPeter Avalos printf("The key's randomart image is:\n"); 147618de8d7fSPeter Avalos printf("%s\n", ra); 147718de8d7fSPeter Avalos xfree(ra); 147818de8d7fSPeter Avalos xfree(fp); 147918de8d7fSPeter Avalos } 148018de8d7fSPeter Avalos 148118de8d7fSPeter Avalos key_free(public); 148218de8d7fSPeter Avalos exit(0); 148318de8d7fSPeter Avalos } 1484