version 1.280, 2015/11/18 08:37:28 |
version 1.298, 2017/03/06 02:03:20 |
|
|
#include <string.h> |
#include <string.h> |
#include <unistd.h> |
#include <unistd.h> |
#include <limits.h> |
#include <limits.h> |
|
#include <locale.h> |
|
|
#include "xmalloc.h" |
#include "xmalloc.h" |
#include "sshkey.h" |
#include "sshkey.h" |
|
|
#include "atomicio.h" |
#include "atomicio.h" |
#include "krl.h" |
#include "krl.h" |
#include "digest.h" |
#include "digest.h" |
|
#include "utf8.h" |
|
|
#ifdef ENABLE_PKCS11 |
#ifdef ENABLE_PKCS11 |
#include "ssh-pkcs11.h" |
#include "ssh-pkcs11.h" |
|
|
*bitsp = sshkey_curve_nid_to_bits(nid); |
*bitsp = sshkey_curve_nid_to_bits(nid); |
if (*bitsp == 0) |
if (*bitsp == 0) |
*bitsp = DEFAULT_BITS_ECDSA; |
*bitsp = DEFAULT_BITS_ECDSA; |
} |
} else |
else |
|
#endif |
#endif |
*bitsp = DEFAULT_BITS; |
*bitsp = DEFAULT_BITS; |
} |
} |
|
|
sshbuf_free(b); |
sshbuf_free(b); |
|
|
/* try the key */ |
/* try the key */ |
if (sshkey_sign(key, &sig, &slen, data, sizeof(data), 0) != 0 || |
if (sshkey_sign(key, &sig, &slen, data, sizeof(data), NULL, 0) != 0 || |
sshkey_verify(key, sig, slen, data, sizeof(data), 0) != 0) { |
sshkey_verify(key, sig, slen, data, sizeof(data), 0) != 0) { |
sshkey_free(key); |
sshkey_free(key); |
free(sig); |
free(sig); |
|
|
ra = sshkey_fingerprint(public, fingerprint_hash, SSH_FP_RANDOMART); |
ra = sshkey_fingerprint(public, fingerprint_hash, SSH_FP_RANDOMART); |
if (fp == NULL || ra == NULL) |
if (fp == NULL || ra == NULL) |
fatal("%s: sshkey_fingerprint failed", __func__); |
fatal("%s: sshkey_fingerprint failed", __func__); |
printf("%u %s %s (%s)\n", sshkey_size(public), fp, |
mprintf("%u %s %s (%s)\n", sshkey_size(public), fp, |
comment ? comment : "no comment", sshkey_type(public)); |
comment ? comment : "no comment", sshkey_type(public)); |
if (log_level >= SYSLOG_LEVEL_VERBOSE) |
if (log_level >= SYSLOG_LEVEL_VERBOSE) |
printf("%s\n", ra); |
printf("%s\n", ra); |
|
|
{ |
{ |
FILE *f; |
FILE *f; |
struct sshkey *public = NULL; |
struct sshkey *public = NULL; |
char *comment = NULL, *cp, *ep, line[16*1024]; |
char *comment = NULL, *cp, *ep, line[SSH_MAX_PUBKEY_BYTES]; |
int i, invalid = 1; |
int i, invalid = 1; |
const char *path; |
const char *path; |
long int lnum = 0; |
u_long lnum = 0; |
|
|
if (!have_identity) |
if (!have_identity) |
ask_filename(pw, "Enter file in which the key is"); |
ask_filename(pw, "Enter file in which the key is"); |
|
|
} |
} |
/* Retry after parsing leading hostname/key options */ |
/* Retry after parsing leading hostname/key options */ |
if (public == NULL && (public = try_read_key(&cp)) == NULL) { |
if (public == NULL && (public = try_read_key(&cp)) == NULL) { |
debug("%s:%ld: not a public key", path, lnum); |
debug("%s:%lu: not a public key", path, lnum); |
continue; |
continue; |
} |
} |
|
|
|
|
struct known_hosts_ctx *ctx = (struct known_hosts_ctx *)_ctx; |
struct known_hosts_ctx *ctx = (struct known_hosts_ctx *)_ctx; |
char *hashed, *cp, *hosts, *ohosts; |
char *hashed, *cp, *hosts, *ohosts; |
int has_wild = l->hosts && strcspn(l->hosts, "*?!") != strlen(l->hosts); |
int has_wild = l->hosts && strcspn(l->hosts, "*?!") != strlen(l->hosts); |
|
int was_hashed = l->hosts && l->hosts[0] == HASH_DELIM; |
|
|
switch (l->status) { |
switch (l->status) { |
case HKF_STATUS_OK: |
case HKF_STATUS_OK: |
|
|
* Don't hash hosts already already hashed, with wildcard |
* Don't hash hosts already already hashed, with wildcard |
* characters or a CA/revocation marker. |
* characters or a CA/revocation marker. |
*/ |
*/ |
if ((l->match & HKF_MATCH_HOST_HASHED) != 0 || |
if (was_hashed || has_wild || l->marker != MRK_NONE) { |
has_wild || l->marker != MRK_NONE) { |
|
fprintf(ctx->out, "%s\n", l->line); |
fprintf(ctx->out, "%s\n", l->line); |
if (has_wild && !find_host) { |
if (has_wild && !find_host) { |
logit("%s:%ld: ignoring host name " |
logit("%s:%lu: ignoring host name " |
"with wildcard: %.64s", l->path, |
"with wildcard: %.64s", l->path, |
l->linenum, l->hosts); |
l->linenum, l->hosts); |
} |
} |
|
|
case HKF_STATUS_INVALID: |
case HKF_STATUS_INVALID: |
/* Retain invalid lines, but mark file as invalid. */ |
/* Retain invalid lines, but mark file as invalid. */ |
ctx->invalid = 1; |
ctx->invalid = 1; |
logit("%s:%ld: invalid line", l->path, l->linenum); |
logit("%s:%lu: invalid line", l->path, l->linenum); |
/* FALLTHROUGH */ |
/* FALLTHROUGH */ |
default: |
default: |
fprintf(ctx->out, "%s\n", l->line); |
fprintf(ctx->out, "%s\n", l->line); |
|
|
*/ |
*/ |
ctx->found_key = 1; |
ctx->found_key = 1; |
if (!quiet) |
if (!quiet) |
printf("# Host %s found: line %ld\n", |
printf("# Host %s found: line %lu\n", |
ctx->host, l->linenum); |
ctx->host, l->linenum); |
} |
} |
return 0; |
return 0; |
} else if (find_host) { |
} else if (find_host) { |
ctx->found_key = 1; |
ctx->found_key = 1; |
if (!quiet) { |
if (!quiet) { |
printf("# Host %s found: line %ld %s\n", |
printf("# Host %s found: line %lu %s\n", |
ctx->host, |
ctx->host, |
l->linenum, l->marker == MRK_CA ? "CA" : |
l->linenum, l->marker == MRK_CA ? "CA" : |
(l->marker == MRK_REVOKE ? "REVOKED" : "")); |
(l->marker == MRK_REVOKE ? "REVOKED" : "")); |
|
|
known_hosts_hash(l, ctx); |
known_hosts_hash(l, ctx); |
else if (print_fingerprint) { |
else if (print_fingerprint) { |
fp = sshkey_fingerprint(l->key, fptype, rep); |
fp = sshkey_fingerprint(l->key, fptype, rep); |
printf("%s %s %s %s\n", ctx->host, |
mprintf("%s %s %s %s\n", ctx->host, |
sshkey_type(l->key), fp, l->comment); |
sshkey_type(l->key), fp, l->comment); |
free(fp); |
free(fp); |
} else |
} else |
|
|
/* Retain non-matching hosts when deleting */ |
/* Retain non-matching hosts when deleting */ |
if (l->status == HKF_STATUS_INVALID) { |
if (l->status == HKF_STATUS_INVALID) { |
ctx->invalid = 1; |
ctx->invalid = 1; |
logit("%s:%ld: invalid line", l->path, l->linenum); |
logit("%s:%lu: invalid line", l->path, l->linenum); |
} |
} |
fprintf(ctx->out, "%s\n", l->line); |
fprintf(ctx->out, "%s\n", l->line); |
} |
} |
|
|
foreach_options |= print_fingerprint ? HKF_WANT_PARSE_KEY : 0; |
foreach_options |= print_fingerprint ? HKF_WANT_PARSE_KEY : 0; |
if ((r = hostkeys_foreach(identity_file, |
if ((r = hostkeys_foreach(identity_file, |
hash_hosts ? known_hosts_hash : known_hosts_find_delete, &ctx, |
hash_hosts ? known_hosts_hash : known_hosts_find_delete, &ctx, |
name, NULL, foreach_options)) != 0) |
name, NULL, foreach_options)) != 0) { |
|
if (inplace) |
|
unlink(tmp); |
fatal("%s: hostkeys_foreach failed: %s", __func__, ssh_err(r)); |
fatal("%s: hostkeys_foreach failed: %s", __func__, ssh_err(r)); |
|
} |
|
|
if (inplace) |
if (inplace) |
fclose(ctx.out); |
fclose(ctx.out); |
|
|
fatal("Failed to load key %s: %s", identity_file, ssh_err(r)); |
fatal("Failed to load key %s: %s", identity_file, ssh_err(r)); |
} |
} |
if (comment) |
if (comment) |
printf("Key has comment '%s'\n", comment); |
mprintf("Key has comment '%s'\n", comment); |
|
|
/* Ask the new passphrase (twice). */ |
/* Ask the new passphrase (twice). */ |
if (identity_new_passphrase) { |
if (identity_new_passphrase) { |
|
|
identity_file, ssh_err(r)); |
identity_file, ssh_err(r)); |
} |
} |
} |
} |
/* XXX what about new-format keys? */ |
|
if (private->type != KEY_RSA1) { |
if (private->type != KEY_RSA1 && private->type != KEY_ED25519 && |
error("Comments are only supported for RSA1 keys."); |
!use_new_format) { |
|
error("Comments are only supported for RSA1 or keys stored in " |
|
"the new format (-o)."); |
explicit_bzero(passphrase, strlen(passphrase)); |
explicit_bzero(passphrase, strlen(passphrase)); |
sshkey_free(private); |
sshkey_free(private); |
exit(1); |
exit(1); |
} |
} |
printf("Key now has comment '%s'\n", comment); |
if (comment) |
|
printf("Key now has comment '%s'\n", comment); |
|
else |
|
printf("Key now has no comment\n"); |
|
|
if (identity_comment) { |
if (identity_comment) { |
strlcpy(new_comment, identity_comment, sizeof(new_comment)); |
strlcpy(new_comment, identity_comment, sizeof(new_comment)); |
|
|
exit(0); |
exit(0); |
} |
} |
|
|
static const char * |
|
fmt_validity(u_int64_t valid_from, u_int64_t valid_to) |
|
{ |
|
char from[32], to[32]; |
|
static char ret[64]; |
|
time_t tt; |
|
struct tm *tm; |
|
|
|
*from = *to = '\0'; |
|
if (valid_from == 0 && valid_to == 0xffffffffffffffffULL) |
|
return "forever"; |
|
|
|
if (valid_from != 0) { |
|
/* XXX revisit INT_MAX in 2038 :) */ |
|
tt = valid_from > INT_MAX ? INT_MAX : valid_from; |
|
tm = localtime(&tt); |
|
strftime(from, sizeof(from), "%Y-%m-%dT%H:%M:%S", tm); |
|
} |
|
if (valid_to != 0xffffffffffffffffULL) { |
|
/* XXX revisit INT_MAX in 2038 :) */ |
|
tt = valid_to > INT_MAX ? INT_MAX : valid_to; |
|
tm = localtime(&tt); |
|
strftime(to, sizeof(to), "%Y-%m-%dT%H:%M:%S", tm); |
|
} |
|
|
|
if (valid_from == 0) { |
|
snprintf(ret, sizeof(ret), "before %s", to); |
|
return ret; |
|
} |
|
if (valid_to == 0xffffffffffffffffULL) { |
|
snprintf(ret, sizeof(ret), "after %s", from); |
|
return ret; |
|
} |
|
|
|
snprintf(ret, sizeof(ret), "from %s to %s", from, to); |
|
return ret; |
|
} |
|
|
|
static void |
static void |
add_flag_option(struct sshbuf *c, const char *name) |
add_flag_option(struct sshbuf *c, const char *name) |
{ |
{ |
|
|
int r, i, fd; |
int r, i, fd; |
u_int n; |
u_int n; |
struct sshkey *ca, *public; |
struct sshkey *ca, *public; |
char *otmp, *tmp, *cp, *out, *comment, **plist = NULL; |
char valid[64], *otmp, *tmp, *cp, *out, *comment, **plist = NULL; |
FILE *f; |
FILE *f; |
|
|
#ifdef ENABLE_PKCS11 |
#ifdef ENABLE_PKCS11 |
|
|
ca = load_identity(tmp); |
ca = load_identity(tmp); |
free(tmp); |
free(tmp); |
|
|
|
if (key_type_name != NULL && |
|
sshkey_type_from_name(key_type_name) != ca->type) { |
|
fatal("CA key type %s doesn't match specified %s", |
|
sshkey_ssh_name(ca), key_type_name); |
|
} |
|
|
for (i = 0; i < argc; i++) { |
for (i = 0; i < argc; i++) { |
/* Split list of principals */ |
/* Split list of principals */ |
n = 0; |
n = 0; |
|
|
&public->cert->signature_key)) != 0) |
&public->cert->signature_key)) != 0) |
fatal("key_from_private (ca key): %s", ssh_err(r)); |
fatal("key_from_private (ca key): %s", ssh_err(r)); |
|
|
if (sshkey_certify(public, ca) != 0) |
if ((r = sshkey_certify(public, ca, key_type_name)) != 0) |
fatal("Couldn't not certify key %s", tmp); |
fatal("Couldn't certify key %s: %s", tmp, ssh_err(r)); |
|
|
if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0) |
if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0) |
*cp = '\0'; |
*cp = '\0'; |
|
|
fclose(f); |
fclose(f); |
|
|
if (!quiet) { |
if (!quiet) { |
|
sshkey_format_cert_validity(public->cert, |
|
valid, sizeof(valid)); |
logit("Signed %s key %s: id \"%s\" serial %llu%s%s " |
logit("Signed %s key %s: id \"%s\" serial %llu%s%s " |
"valid %s", sshkey_cert_type(public), |
"valid %s", sshkey_cert_type(public), |
out, public->cert->key_id, |
out, public->cert->key_id, |
(unsigned long long)public->cert->serial, |
(unsigned long long)public->cert->serial, |
cert_principals != NULL ? " for " : "", |
cert_principals != NULL ? " for " : "", |
cert_principals != NULL ? cert_principals : "", |
cert_principals != NULL ? cert_principals : "", |
fmt_validity(cert_valid_from, cert_valid_to)); |
valid); |
} |
} |
|
|
sshkey_free(public); |
sshkey_free(public); |
|
|
char buf[32], *fmt; |
char buf[32], *fmt; |
|
|
/* |
/* |
* POSIX strptime says "The application shall ensure that there |
* POSIX strptime says "The application shall ensure that there |
* is white-space or other non-alphanumeric characters between |
* is white-space or other non-alphanumeric characters between |
* any two conversion specifications" so arrange things this way. |
* any two conversion specifications" so arrange things this way. |
*/ |
*/ |
|
|
static void |
static void |
print_cert(struct sshkey *key) |
print_cert(struct sshkey *key) |
{ |
{ |
char *key_fp, *ca_fp; |
char valid[64], *key_fp, *ca_fp; |
u_int i; |
u_int i; |
|
|
key_fp = sshkey_fingerprint(key, fingerprint_hash, SSH_FP_DEFAULT); |
key_fp = sshkey_fingerprint(key, fingerprint_hash, SSH_FP_DEFAULT); |
|
|
fingerprint_hash, SSH_FP_DEFAULT); |
fingerprint_hash, SSH_FP_DEFAULT); |
if (key_fp == NULL || ca_fp == NULL) |
if (key_fp == NULL || ca_fp == NULL) |
fatal("%s: sshkey_fingerprint fail", __func__); |
fatal("%s: sshkey_fingerprint fail", __func__); |
|
sshkey_format_cert_validity(key->cert, valid, sizeof(valid)); |
|
|
printf(" Type: %s %s certificate\n", sshkey_ssh_name(key), |
printf(" Type: %s %s certificate\n", sshkey_ssh_name(key), |
sshkey_cert_type(key)); |
sshkey_cert_type(key)); |
|
|
sshkey_type(key->cert->signature_key), ca_fp); |
sshkey_type(key->cert->signature_key), ca_fp); |
printf(" Key ID: \"%s\"\n", key->cert->key_id); |
printf(" Key ID: \"%s\"\n", key->cert->key_id); |
printf(" Serial: %llu\n", (unsigned long long)key->cert->serial); |
printf(" Serial: %llu\n", (unsigned long long)key->cert->serial); |
printf(" Valid: %s\n", |
printf(" Valid: %s\n", valid); |
fmt_validity(key->cert->valid_after, key->cert->valid_before)); |
|
printf(" Principals: "); |
printf(" Principals: "); |
if (key->cert->nprincipals == 0) |
if (key->cert->nprincipals == 0) |
printf("(none)\n"); |
printf("(none)\n"); |
|
|
struct stat st; |
struct stat st; |
int r, is_stdin = 0, ok = 0; |
int r, is_stdin = 0, ok = 0; |
FILE *f; |
FILE *f; |
char *cp, line[2048]; |
char *cp, line[SSH_MAX_PUBKEY_BYTES]; |
const char *path; |
const char *path; |
long int lnum = 0; |
u_long lnum = 0; |
|
|
if (!have_identity) |
if (!have_identity) |
ask_filename(pw, "Enter file in which the key is"); |
ask_filename(pw, "Enter file in which the key is"); |
|
|
close(fd); |
close(fd); |
sshbuf_free(kbuf); |
sshbuf_free(kbuf); |
ssh_krl_free(krl); |
ssh_krl_free(krl); |
if (ca != NULL) |
sshkey_free(ca); |
sshkey_free(ca); |
|
} |
} |
|
|
static void |
static void |
|
|
} |
} |
#endif |
#endif |
|
|
|
#ifdef WITH_SSH1 |
|
# define RSA1_USAGE " | rsa1" |
|
#else |
|
# define RSA1_USAGE "" |
|
#endif |
|
|
static void |
static void |
usage(void) |
usage(void) |
{ |
{ |
fprintf(stderr, |
fprintf(stderr, |
"usage: ssh-keygen [-q] [-b bits] [-t dsa | ecdsa | ed25519 | rsa | rsa1]\n" |
"usage: ssh-keygen [-q] [-b bits] [-t dsa | ecdsa | ed25519 | rsa%s]\n" |
" [-N new_passphrase] [-C comment] [-f output_keyfile]\n" |
" [-N new_passphrase] [-C comment] [-f output_keyfile]\n" |
" ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile]\n" |
" ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile]\n" |
" ssh-keygen -i [-m key_format] [-f input_keyfile]\n" |
" ssh-keygen -i [-m key_format] [-f input_keyfile]\n" |
|
|
" ssh-keygen -y [-f input_keyfile]\n" |
" ssh-keygen -y [-f input_keyfile]\n" |
" ssh-keygen -c [-P passphrase] [-C comment] [-f keyfile]\n" |
" ssh-keygen -c [-P passphrase] [-C comment] [-f keyfile]\n" |
" ssh-keygen -l [-v] [-E fingerprint_hash] [-f input_keyfile]\n" |
" ssh-keygen -l [-v] [-E fingerprint_hash] [-f input_keyfile]\n" |
" ssh-keygen -B [-f input_keyfile]\n"); |
" ssh-keygen -B [-f input_keyfile]\n", RSA1_USAGE); |
#ifdef ENABLE_PKCS11 |
#ifdef ENABLE_PKCS11 |
fprintf(stderr, |
fprintf(stderr, |
" ssh-keygen -D pkcs11\n"); |
" ssh-keygen -D pkcs11\n"); |
|
|
extern int optind; |
extern int optind; |
extern char *optarg; |
extern char *optarg; |
|
|
|
ssh_malloc_init(); /* must be called before any mallocs */ |
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ |
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ |
sanitise_stdfd(); |
sanitise_stdfd(); |
|
|
OpenSSL_add_all_algorithms(); |
OpenSSL_add_all_algorithms(); |
log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1); |
log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1); |
|
|
|
setlocale(LC_CTYPE, ""); |
|
|
/* we need this for the home * directory. */ |
/* we need this for the home * directory. */ |
pw = getpwuid(getuid()); |
pw = getpwuid(getuid()); |
if (!pw) |
if (!pw) |
|
|
break; |
break; |
case 'J': |
case 'J': |
lines_to_process = strtoul(optarg, NULL, 10); |
lines_to_process = strtoul(optarg, NULL, 10); |
break; |
break; |
case 'j': |
case 'j': |
start_lineno = strtoul(optarg, NULL, 10); |
start_lineno = strtoul(optarg, NULL, 10); |
break; |
break; |
case 'K': |
case 'K': |
if (strlen(optarg) >= PATH_MAX) |
if (strlen(optarg) >= PATH_MAX) |
fatal("Checkpoint filename too long"); |
fatal("Checkpoint filename too long"); |