[PATCH] Use canonical hostname for DNS SSHFP lookup
Jan Andres
jandres at gmx.net
Mon Nov 29 04:57:57 EST 2010
Here is a patch for the second approach. This one required some
butchering of the getrrsetbyname() code in order to
- add an option to use res_search() instead of res_query() (i.e. use the
search path from resolv.conf)
- return the actual canonical name when confronted with CNAME/DNAME RRs
(without this change, it would return the name of the CNAME as the
canonical name).
Regards,
Jan
diff -ur openssh/dns.c openssh-sshfp/dns.c
--- openssh/dns.c 2010-08-31 14:41:14.000000000 +0200
+++ openssh-sshfp/dns.c 2010-11-28 18:45:41.594577525 +0100
@@ -173,7 +173,7 @@
*/
int
verify_host_key_dns(const char *hostname, struct sockaddr *address,
- Key *hostkey, int *flags)
+ Key *hostkey, int *flags, const char *canohost)
{
u_int counter;
int result;
@@ -201,16 +201,25 @@
}
result = getrrsetbyname(hostname, DNS_RDATACLASS_IN,
- DNS_RDATATYPE_SSHFP, 0, &fingerprints);
+ DNS_RDATATYPE_SSHFP, RRSET_SEARCH, &fingerprints);
if (result) {
verbose("DNS lookup error: %s", dns_result_totext(result));
return -1;
}
+ debug3("canonical hostname of SSHFP RRset is %s",
+ fingerprints->rri_name);
+
if (fingerprints->rri_flags & RRSET_VALIDATED) {
- *flags |= DNS_VERIFY_SECURE;
- debug("found %d secure fingerprints in DNS",
- fingerprints->rri_nrdatas);
+ if (strcasecmp(fingerprints->rri_name, canohost) == 0) {
+ *flags |= DNS_VERIFY_SECURE;
+ debug("found %d secure fingerprints in DNS",
+ fingerprints->rri_nrdatas);
+ } else {
+ debug("found %d insecure fingerprints in DNS, "
+ "not trusted due to host name mismatch",
+ fingerprints->rri_nrdatas);
+ }
} else {
debug("found %d insecure fingerprints in DNS",
fingerprints->rri_nrdatas);
diff -ur openssh/dns.h openssh-sshfp/dns.h
--- openssh/dns.h 2010-02-26 21:55:05.000000000 +0100
+++ openssh-sshfp/dns.h 2010-11-28 10:34:56.536431386 +0100
@@ -46,7 +46,8 @@
#define DNS_VERIFY_MATCH 0x00000002
#define DNS_VERIFY_SECURE 0x00000004
-int verify_host_key_dns(const char *, struct sockaddr *, Key *, int *);
+int verify_host_key_dns(const char *, struct sockaddr *, Key *, int *,
+ const char *);
int export_dns_rr(const char *, Key *, FILE *, int);
#endif /* DNS_H */
diff -ur openssh/openbsd-compat/fake-rfc2553.c openssh-sshfp/openbsd-compat/fake-rfc2553.c
--- openssh/openbsd-compat/fake-rfc2553.c 2008-07-14 13:37:37.000000000 +0200
+++ openssh-sshfp/openbsd-compat/fake-rfc2553.c 2010-11-28 12:01:24.574267973 +0100
@@ -121,15 +121,23 @@
#ifndef HAVE_GETADDRINFO
static struct
-addrinfo *malloc_ai(int port, u_long addr, const struct addrinfo *hints)
+addrinfo *malloc_ai(int port, u_long addr, const struct addrinfo *hints,
+ const char *canonname)
{
struct addrinfo *ai;
+ int len = sizeof(*ai) + sizeof(struct sockaddr_in);
+ int canonlen = 0;
- ai = malloc(sizeof(*ai) + sizeof(struct sockaddr_in));
+ if (canonname != NULL) {
+ canonlen = strlen (canonname);
+ len += canonlen + 1;
+ }
+
+ ai = malloc(len);
if (ai == NULL)
return (NULL);
- memset(ai, '\0', sizeof(*ai) + sizeof(struct sockaddr_in));
+ memset(ai, '\0', len);
ai->ai_addr = (struct sockaddr *)(ai + 1);
/* XXX -- ssh doesn't use sa_len */
@@ -138,6 +146,11 @@
((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
+
+ if (canonname != NULL) {
+ ai->ai_canonname = ((char *)ai->ai_addr) + sizeof(struct sockaddr_in);
+ strlcpy(ai->ai_canonname, canonname, canonlen + 1);
+ }
/* XXX: the following is not generally correct, but does what we want */
if (hints->ai_socktype)
@@ -182,21 +195,24 @@
addr = htonl(0x00000000);
if (hostname && inet_aton(hostname, &in) != 0)
addr = in.s_addr;
- *res = malloc_ai(port, addr, hints);
+ *res = malloc_ai(port, addr, hints, NULL);
if (*res == NULL)
return (EAI_MEMORY);
return (0);
}
if (!hostname) {
- *res = malloc_ai(port, htonl(0x7f000001), hints);
+ *res = malloc_ai(port, htonl(0x7f000001), hints, NULL);
if (*res == NULL)
return (EAI_MEMORY);
return (0);
}
if (inet_aton(hostname, &in)) {
- *res = malloc_ai(port, in.s_addr, hints);
+ const char *canonname = NULL;
+ if (hints && hints->ai_flags & AI_CANONNAME)
+ canonname = hostname;
+ *res = malloc_ai(port, in.s_addr, hints, canonname);
if (*res == NULL)
return (EAI_MEMORY);
return (0);
@@ -213,8 +229,12 @@
cur = prev = *res = NULL;
for (i = 0; hp->h_addr_list[i]; i++) {
struct in_addr *in = (struct in_addr *)hp->h_addr_list[i];
+ const char *canonname = NULL;
+
+ if (!prev && hints && hints->ai_flags & AI_CANONNAME)
+ canonname = hp->h_name;
- cur = malloc_ai(port, in->s_addr, hints);
+ cur = malloc_ai(port, in->s_addr, hints, canonname);
if (cur == NULL) {
if (*res != NULL)
freeaddrinfo(*res);
diff -ur openssh/openbsd-compat/getrrsetbyname.c openssh-sshfp/openbsd-compat/getrrsetbyname.c
--- openssh/openbsd-compat/getrrsetbyname.c 2009-07-13 03:38:23.000000000 +0200
+++ openssh-sshfp/openbsd-compat/getrrsetbyname.c 2010-11-28 18:49:13.886195349 +0100
@@ -209,8 +209,8 @@
goto fail;
}
- /* don't allow flags yet, unimplemented */
- if (flags) {
+ /* check for unsupported flags */
+ if (flags & ~RRSET_SEARCH) {
result = ERRSET_INVAL;
goto fail;
}
@@ -232,8 +232,13 @@
#endif /* RES_USE_DNSEC */
/* make query */
- length = res_query(hostname, (signed int) rdclass, (signed int) rdtype,
- answer, sizeof(answer));
+ if (flags & RRSET_SEARCH)
+ length = res_search(hostname, (signed int) rdclass,
+ (signed int) rdtype, answer, sizeof(answer));
+ else
+ length = res_query(hostname, (signed int) rdclass,
+ (signed int) rdtype, answer, sizeof(answer));
+
if (length < 0) {
switch(h_errno) {
case HOST_NOT_FOUND:
@@ -277,13 +282,6 @@
rrset->rri_flags |= RRSET_VALIDATED;
#endif
- /* copy name from answer section */
- rrset->rri_name = strdup(response->answer->name);
- if (rrset->rri_name == NULL) {
- result = ERRSET_NOMEMORY;
- goto fail;
- }
-
/* count answers */
rrset->rri_nrdatas = count_dns_rr(response->answer, rrset->rri_rdclass,
rrset->rri_rdtype);
@@ -314,8 +312,17 @@
rdata = NULL;
if (rr->class == rrset->rri_rdclass &&
- rr->type == rrset->rri_rdtype)
+ rr->type == rrset->rri_rdtype) {
+ /* extract canonical name from first data RR */
+ if (index_ans == 0) {
+ rrset->rri_name = strdup(rr->name);
+ if (rrset->rri_name == NULL) {
+ result = ERRSET_NOMEMORY;
+ goto fail;
+ }
+ }
rdata = &rrset->rri_rdatas[index_ans++];
+ }
if (rr->class == rrset->rri_rdclass &&
rr->type == T_RRSIG)
Only in openssh-sshfp/openbsd-compat: .getrrsetbyname.c.swp
diff -ur openssh/openbsd-compat/getrrsetbyname.h openssh-sshfp/openbsd-compat/getrrsetbyname.h
--- openssh/openbsd-compat/getrrsetbyname.h 2007-10-26 08:26:50.000000000 +0200
+++ openssh-sshfp/openbsd-compat/getrrsetbyname.h 2010-11-28 14:48:32.393987287 +0100
@@ -69,6 +69,13 @@
/*
* Flags for getrrsetbyname()
*/
+#ifndef RRSET_SEARCH
+# define RRSET_SEARCH 1
+#endif
+
+/*
+ * Flags for rrsetinfo.rri_flags
+ */
#ifndef RRSET_VALIDATED
# define RRSET_VALIDATED 1
#endif
diff -ur openssh/roaming_client.c openssh-sshfp/roaming_client.c
--- openssh/roaming_client.c 2010-01-26 02:53:06.000000000 +0100
+++ openssh-sshfp/roaming_client.c 2010-11-28 09:49:06.626052834 +0100
@@ -263,7 +263,7 @@
if (ssh_connect(host, &hostaddr, options.port,
options.address_family, 1, &timeout_ms,
options.tcp_keep_alive, options.use_privileged_port,
- options.proxy_command) == 0 && roaming_resume() == 0) {
+ options.proxy_command, NULL) == 0 && roaming_resume() == 0) {
packet_restore_state();
reenter_guard = 0;
fprintf(stderr, "[connection resumed]\n");
diff -ur openssh/ssh.c openssh-sshfp/ssh.c
--- openssh/ssh.c 2010-11-20 05:19:38.000000000 +0100
+++ openssh-sshfp/ssh.c 2010-11-27 23:43:12.843314405 +0100
@@ -229,6 +229,7 @@
extern char *optarg;
struct servent *sp;
Forward fwd;
+ char *canohost;
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
sanitise_stdfd();
@@ -760,7 +761,7 @@
#else
original_effective_uid == 0 && options.use_privileged_port,
#endif
- options.proxy_command) != 0)
+ options.proxy_command, &canohost) != 0)
exit(255);
if (timeout_ms > 0)
@@ -880,7 +881,7 @@
/* Log into the remote system. Never returns if the login fails. */
ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr,
- pw, timeout_ms);
+ pw, timeout_ms, canohost);
if (packet_connection_is_on_socket()) {
verbose("Authenticated to %s ([%s]:%d).", host,
@@ -889,6 +890,8 @@
verbose("Authenticated to %s (via proxy).", host);
}
+ xfree (canohost);
+
/* We no longer need the private host keys. Clear them now. */
if (sensitive_data.nkeys != 0) {
for (i = 0; i < sensitive_data.nkeys; i++) {
diff -ur openssh/sshconnect1.c openssh-sshfp/sshconnect1.c
--- openssh/sshconnect1.c 2006-11-07 13:14:42.000000000 +0100
+++ openssh-sshfp/sshconnect1.c 2010-11-27 23:57:11.267747490 +0100
@@ -535,7 +535,7 @@
debug("Received server public key (%d bits) and host key (%d bits).",
BN_num_bits(server_key->rsa->n), BN_num_bits(host_key->rsa->n));
- if (verify_host_key(host, hostaddr, host_key) == -1)
+ if (verify_host_key(host, hostaddr, host_key, NULL) == -1)
fatal("Host key verification failed.");
client_flags = SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN;
diff -ur openssh/sshconnect2.c openssh-sshfp/sshconnect2.c
--- openssh/sshconnect2.c 2010-09-24 14:11:14.000000000 +0200
+++ openssh-sshfp/sshconnect2.c 2010-11-27 23:38:36.154046251 +0100
@@ -90,24 +90,26 @@
char *xxx_host;
struct sockaddr *xxx_hostaddr;
+const char *xxx_canohost;
Kex *xxx_kex = NULL;
static int
verify_host_key_callback(Key *hostkey)
{
- if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1)
+ if (verify_host_key(xxx_host, xxx_hostaddr, hostkey, xxx_canohost) == -1)
fatal("Host key verification failed.");
return 0;
}
void
-ssh_kex2(char *host, struct sockaddr *hostaddr)
+ssh_kex2(char *host, struct sockaddr *hostaddr, const char *canohost)
{
Kex *kex;
xxx_host = host;
xxx_hostaddr = hostaddr;
+ xxx_canohost = canohost;
if (options.ciphers == (char *)-1) {
logit("No valid ciphers for protocol version 2 given, using defaults.");
diff -ur openssh/sshconnect.c openssh-sshfp/sshconnect.c
--- openssh/sshconnect.c 2010-11-28 12:04:32.127050308 +0100
+++ openssh-sshfp/sshconnect.c 2010-11-28 10:32:12.357225689 +0100
@@ -335,7 +335,8 @@
int
ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
u_short port, int family, int connection_attempts, int *timeout_ms,
- int want_keepalive, int needpriv, const char *proxy_command)
+ int want_keepalive, int needpriv, const char *proxy_command,
+ char **canohost)
{
int gaierr;
int on = 1;
@@ -352,6 +353,8 @@
/* No proxy command. */
memset(&hints, 0, sizeof(hints));
+ if (canohost != NULL)
+ hints.ai_flags = AI_CANONNAME;
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
snprintf(strport, sizeof strport, "%u", port);
@@ -359,6 +362,9 @@
fatal("%s: Could not resolve hostname %.100s: %s", __progname,
host, ssh_gai_strerror(gaierr));
+ if (canohost != NULL)
+ *canohost = xstrdup (aitop->ai_canonname);
+
for (attempt = 0; attempt < connection_attempts; attempt++) {
if (attempt > 0) {
/* Sleep a moment before retrying. */
@@ -1061,14 +1067,16 @@
/* returns 0 if key verifies or -1 if key does NOT verify */
int
-verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
+verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
+ const char *canohost)
{
struct stat st;
int flags = 0;
/* XXX certs are not yet supported for DNS */
if (!key_is_cert(host_key) && options.verify_host_key_dns &&
- verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) {
+ canohost != NULL &&
+ verify_host_key_dns(host, hostaddr, host_key, &flags, canohost) == 0) {
if (flags & DNS_VERIFY_FOUND) {
@@ -1108,7 +1116,8 @@
*/
void
ssh_login(Sensitive *sensitive, const char *orighost,
- struct sockaddr *hostaddr, struct passwd *pw, int timeout_ms)
+ struct sockaddr *hostaddr, struct passwd *pw, int timeout_ms,
+ const char *canohost)
{
char *host, *cp;
char *server_user, *local_user;
@@ -1131,7 +1140,7 @@
/* key exchange */
/* authenticate user */
if (compat20) {
- ssh_kex2(host, hostaddr);
+ ssh_kex2(host, hostaddr, canohost);
ssh_userauth2(local_user, server_user, host, sensitive);
} else {
ssh_kex(host, hostaddr);
diff -ur openssh/sshconnect.h openssh-sshfp/sshconnect.h
--- openssh/sshconnect.h 2010-10-07 13:07:33.000000000 +0200
+++ openssh-sshfp/sshconnect.h 2010-11-28 10:34:37.941783851 +0100
@@ -33,18 +33,19 @@
int
ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int,
- int *, int, int, const char *);
+ int *, int, int, const char *, char **);
void ssh_kill_proxy_command(void);
void
-ssh_login(Sensitive *, const char *, struct sockaddr *, struct passwd *, int);
+ssh_login(Sensitive *, const char *, struct sockaddr *, struct passwd *, int,
+ const char *);
void ssh_exchange_identification(int);
-int verify_host_key(char *, struct sockaddr *, Key *);
+int verify_host_key(char *, struct sockaddr *, Key *, const char *);
void ssh_kex(char *, struct sockaddr *);
-void ssh_kex2(char *, struct sockaddr *);
+void ssh_kex2(char *, struct sockaddr *, const char *);
void ssh_userauth1(const char *, const char *, char *, Sensitive *);
void ssh_userauth2(const char *, const char *, char *, Sensitive *);
--
Jan Andres <jandres at gmx.net>
More information about the openssh-unix-dev
mailing list