From 1c6e4ea97ef72a290ee12a2f13880c005961a8be Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Wed, 23 May 2012 03:28:29 +0000 Subject: add support for RFC6594 SSHFP DNS records for ECDSA key types. patch from bugzilla-m67 AT nulld.me in bz#1978; ok + tweak markus@ --- usr.bin/ssh/dns.c | 103 +++++++++++++++++++++++++++++++---------------- usr.bin/ssh/dns.h | 15 ++++--- usr.bin/ssh/key.c | 5 ++- usr.bin/ssh/key.h | 5 ++- usr.bin/ssh/ssh-keygen.c | 4 +- 5 files changed, 88 insertions(+), 44 deletions(-) diff --git a/usr.bin/ssh/dns.c b/usr.bin/ssh/dns.c index b4be46ad868..b17e61152ed 100644 --- a/usr.bin/ssh/dns.c +++ b/usr.bin/ssh/dns.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dns.c,v 1.27 2010/08/31 11:54:45 djm Exp $ */ +/* $OpenBSD: dns.c,v 1.28 2012/05/23 03:28:28 djm Exp $ */ /* * Copyright (c) 2003 Wesley Griffin. All rights reserved. @@ -75,27 +75,46 @@ dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type, u_char **digest, u_int *digest_len, Key *key) { int success = 0; + enum fp_type fp_type = 0; switch (key->type) { case KEY_RSA: *algorithm = SSHFP_KEY_RSA; + if (!*digest_type) + *digest_type = SSHFP_HASH_SHA1; break; case KEY_DSA: *algorithm = SSHFP_KEY_DSA; + if (!*digest_type) + *digest_type = SSHFP_HASH_SHA1; + break; + case KEY_ECDSA: + *algorithm = SSHFP_KEY_ECDSA; + if (!*digest_type) + *digest_type = SSHFP_HASH_SHA256; break; - /* XXX KEY_ECDSA */ default: *algorithm = SSHFP_KEY_RESERVED; /* 0 */ + *digest_type = SSHFP_HASH_RESERVED; /* 0 */ + } + + switch (*digest_type) { + case SSHFP_HASH_SHA1: + fp_type = SSH_FP_SHA1; + break; + case SSHFP_HASH_SHA256: + fp_type = SSH_FP_SHA256; + break; + default: + *digest_type = SSHFP_HASH_RESERVED; /* 0 */ } - if (*algorithm) { - *digest_type = SSHFP_HASH_SHA1; - *digest = key_fingerprint_raw(key, SSH_FP_SHA1, digest_len); + if (*algorithm && *digest_type) { + *digest = key_fingerprint_raw(key, fp_type, digest_len); if (*digest == NULL) fatal("dns_read_key: null from key_fingerprint_raw()"); success = 1; } else { - *digest_type = SSHFP_HASH_RESERVED; *digest = NULL; *digest_len = 0; success = 0; @@ -177,7 +196,7 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address, struct rrsetinfo *fingerprints = NULL; u_int8_t hostkey_algorithm; - u_int8_t hostkey_digest_type; + u_int8_t hostkey_digest_type = SSHFP_HASH_RESERVED; u_char *hostkey_digest; u_int hostkey_digest_len; @@ -213,7 +232,7 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address, fingerprints->rri_nrdatas); } - /* Initialize host key parameters */ + /* Initialize default host key parameters */ if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type, &hostkey_digest, &hostkey_digest_len, hostkey)) { error("Error calculating host key fingerprint."); @@ -237,16 +256,27 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address, continue; } + if (hostkey_digest_type != dnskey_digest_type) { + hostkey_digest_type = dnskey_digest_type; + xfree(hostkey_digest); + + /* Initialize host key parameters */ + if (!dns_read_key(&hostkey_algorithm, + &hostkey_digest_type, &hostkey_digest, + &hostkey_digest_len, hostkey)) { + error("Error calculating key fingerprint."); + freerrset(fingerprints); + return -1; + } + } + /* Check if the current key is the same as the given key */ if (hostkey_algorithm == dnskey_algorithm && hostkey_digest_type == dnskey_digest_type) { - if (hostkey_digest_len == dnskey_digest_len && - memcmp(hostkey_digest, dnskey_digest, - hostkey_digest_len) == 0) { - + timingsafe_bcmp(hostkey_digest, dnskey_digest, + hostkey_digest_len) == 0) *flags |= DNS_VERIFY_MATCH; - } } xfree(dnskey_digest); } @@ -272,31 +302,36 @@ int export_dns_rr(const char *hostname, Key *key, FILE *f, int generic) { u_int8_t rdata_pubkey_algorithm = 0; - u_int8_t rdata_digest_type = SSHFP_HASH_SHA1; + u_int8_t rdata_digest_type = SSHFP_HASH_RESERVED; + u_int8_t dtype; u_char *rdata_digest; - u_int rdata_digest_len; - - u_int i; + u_int i, rdata_digest_len; int success = 0; - if (dns_read_key(&rdata_pubkey_algorithm, &rdata_digest_type, - &rdata_digest, &rdata_digest_len, key)) { - - if (generic) - fprintf(f, "%s IN TYPE%d \\# %d %02x %02x ", hostname, - DNS_RDATATYPE_SSHFP, 2 + rdata_digest_len, - rdata_pubkey_algorithm, rdata_digest_type); - else - fprintf(f, "%s IN SSHFP %d %d ", hostname, - rdata_pubkey_algorithm, rdata_digest_type); + for (dtype = SSHFP_HASH_SHA1; dtype < SSHFP_HASH_MAX; dtype++) { + rdata_digest_type = dtype; + if (dns_read_key(&rdata_pubkey_algorithm, &rdata_digest_type, + &rdata_digest, &rdata_digest_len, key)) { + if (generic) { + fprintf(f, "%s IN TYPE%d \\# %d %02x %02x ", + hostname, DNS_RDATATYPE_SSHFP, + 2 + rdata_digest_len, + rdata_pubkey_algorithm, rdata_digest_type); + } else { + fprintf(f, "%s IN SSHFP %d %d ", hostname, + rdata_pubkey_algorithm, rdata_digest_type); + } + for (i = 0; i < rdata_digest_len; i++) + fprintf(f, "%02x", rdata_digest[i]); + fprintf(f, "\n"); + xfree(rdata_digest); /* from key_fingerprint_raw() */ + success = 1; + } + } - for (i = 0; i < rdata_digest_len; i++) - fprintf(f, "%02x", rdata_digest[i]); - fprintf(f, "\n"); - xfree(rdata_digest); /* from key_fingerprint_raw() */ - success = 1; - } else { - error("export_dns_rr: unsupported algorithm"); + /* No SSHFP record was generated at all */ + if (success == 0) { + error("%s: unsupported algorithm and/or digest_type", __func__); } return success; diff --git a/usr.bin/ssh/dns.h b/usr.bin/ssh/dns.h index 90cfd7b92ce..d5f42817780 100644 --- a/usr.bin/ssh/dns.h +++ b/usr.bin/ssh/dns.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dns.h,v 1.11 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: dns.h,v 1.12 2012/05/23 03:28:28 djm Exp $ */ /* * Copyright (c) 2003 Wesley Griffin. All rights reserved. @@ -29,14 +29,17 @@ #define DNS_H enum sshfp_types { - SSHFP_KEY_RESERVED, - SSHFP_KEY_RSA, - SSHFP_KEY_DSA + SSHFP_KEY_RESERVED = 0, + SSHFP_KEY_RSA = 1, + SSHFP_KEY_DSA = 2, + SSHFP_KEY_ECDSA = 3 }; enum sshfp_hashes { - SSHFP_HASH_RESERVED, - SSHFP_HASH_SHA1 + SSHFP_HASH_RESERVED = 0, + SSHFP_HASH_SHA1 = 1, + SSHFP_HASH_SHA256 = 2, + SSHFP_HASH_MAX = 3 }; #define DNS_RDATACLASS_IN 1 diff --git a/usr.bin/ssh/key.c b/usr.bin/ssh/key.c index 5761320fbd3..62ed607713c 100644 --- a/usr.bin/ssh/key.c +++ b/usr.bin/ssh/key.c @@ -1,4 +1,4 @@ -/* $OpenBSD: key.c,v 1.98 2011/10/18 04:58:26 djm Exp $ */ +/* $OpenBSD: key.c,v 1.99 2012/05/23 03:28:28 djm Exp $ */ /* * read_bignum(): * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -330,6 +330,9 @@ key_fingerprint_raw(Key *k, enum fp_type dgst_type, u_int *dgst_raw_length) case SSH_FP_SHA1: md = EVP_sha1(); break; + case SSH_FP_SHA256: + md = EVP_sha256(); + break; default: fatal("key_fingerprint_raw: bad digest type %d", dgst_type); diff --git a/usr.bin/ssh/key.h b/usr.bin/ssh/key.h index 1b9b21ceaa8..e891dd71f3e 100644 --- a/usr.bin/ssh/key.h +++ b/usr.bin/ssh/key.h @@ -1,4 +1,4 @@ -/* $OpenBSD: key.h,v 1.33 2010/10/28 11:22:09 djm Exp $ */ +/* $OpenBSD: key.h,v 1.34 2012/05/23 03:28:28 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -46,7 +46,8 @@ enum types { }; enum fp_type { SSH_FP_SHA1, - SSH_FP_MD5 + SSH_FP_MD5, + SSH_FP_SHA256 }; enum fp_rep { SSH_FP_HEX, diff --git a/usr.bin/ssh/ssh-keygen.c b/usr.bin/ssh/ssh-keygen.c index e6cdeba7f94..e0d015eca6c 100644 --- a/usr.bin/ssh/ssh-keygen.c +++ b/usr.bin/ssh/ssh-keygen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.213 2012/02/29 11:21:26 djm Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.214 2012/05/23 03:28:28 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland @@ -2175,6 +2175,8 @@ main(int argc, char **argv) _PATH_HOST_RSA_KEY_FILE, rr_hostname); n += do_print_resource_record(pw, _PATH_HOST_DSA_KEY_FILE, rr_hostname); + n += do_print_resource_record(pw, + _PATH_HOST_ECDSA_KEY_FILE, rr_hostname); if (n == 0) fatal("no keys found."); -- cgit v1.2.3