Dear SSH Maintainers, Recently, DSA had the opportunity to address a DD's request that we begin using SSH certificates to authenticate Debian Project machines to ssh clients. We provided a lengthy reply (see attached), the summary of which is "we publish SSHFP records; use VerifyHostKeyDNS; set up a local caching resolver to avoid MITM attacks". It seems rather cumbersome to have users install a local chaching resolver in order to secure the last mile of DNS queries, so we postulated whether it would be possible to modify openssh such that the ssh client could perform the queries itself. Turns out that this is quite straight forward to implement (see patch, attached). The openssh developers have encapsulated the DNS query code well, and the unbound developers have exposed the right amount of DNS information while still giving access to the raw response. Since we are quite concerned that DDs aren't managing their known_hosts in a secure fashion, we are keen on using SSHFP records .. but only if the DNSSEC last mile issue can be addressed in a relatively easy way for users. We propose that the openssh package be modified as follows: (1) introduce a new ssh_config directive: UnboundConfiguration (2) modify getrrsetbyname() such that if UnboundConfiguration is set, the unbound resolver is used; if not, the libc resolver is used In this way, the standard mode of operation for ssh remains unchanged by default. Users who would like to use SSHFP records in a secure manner would need to set the configuration directive. We would love to see this functionality in wheezy. Our proposed approach is low risk in that it leaves the default mode of operation untouched. From a package maintainer's perspective, it introduces a divergence from upstream (although we are keen to submit this upstream, also) and a new dependency on libunbound. Please let us know your thoughts on the above. Thanks very much, Luca -- Luca Filipozzi Member, Debian System Administration Team
On Tue, May 01, 2012 at 07:14:48PM +0000, Debian Developer via RT wrote: > OpenSSH allows to sign the host pubkeys with another ssh key, which > then can be used in users knownhosts files as a certificate authority. > > That way, Debian people can use a simple one line entry for all the > hosts, rather than manually importing and updating a list deduced from > the db.debian.org overview. Thanks for submitting this request. The introduction of an x509-like PKI for user-to-host (user certs) and host-to-user (host certs) is interesting. The biggest challenge is the certificate revocation mechanism. With traditional ssh-rsa host keys (the ones we publish in LDAP and in /etc/ssh/ssh_known_hosts on every Debian hosts), if we need to revoke a key (because a server is decommissioned or, worse, compromised), we need only remove the public key from LDAP and /etc/ssh/ssh_known_hosts. Unfortunately, this assumes that end users, such as yourself, are doing two things: (1) that you're careful about which certificates you accept (or are using StrictHostKeyChecking yes) and (2) that you're updating your ~/.ssh/known_hosts from an authoritative source periodically. These are fairly significant assumptions. We strongly suspect that the majority of users, even the majority of Debian Developers, are not as careful about host keys as we'd like them to be. Even if they are doing these things, the mechanism is pull-based rather than pushed or triggered. It would be very good if, upon revocation of a compromised server's cert, users would not need be required to do anything. In x509 terms, this would be the equivalent of having a properly working certificate revocation list (CRL) mechanism (which has its own set of problems but let's assume it works for the purposes of this ticket). The introduction of an x509-like PKI mechanism for ssh that does not include a decent CRL mechanism strikes us as being just as weak as the ssh-rsa host key mechanism. We can publish a list of revoked certs but users would have to import these into their known_hosts... so we're back to where we started! Perhaps the correct mechanism is SSHFP (SSH FingerPrint) DNS resource records. Users (rightfully so) would like a pain-free configuration of their ssh clients and administrators would like an automated revocation mechanism. The SSHFP DNS resource records provide this and we're already publishing SSHFP records for Debian machines! Put these two lines in your .ssh/config (remember to delete debian hosts from your .ssh/known_hosts) and you're good to go (sort of; read below): StrictHostKeyChecking yes VerifyHostKeyDNS yes Why "sort of"? The challenge with SSHFP records is authenticating them... that is, preventing MITM attacks. DNSSEC can help, here, but only if you trust the DNS replies you're receiving (which means trusting your resolver and having a secure connection to it). The best way to ensure this is to install a local caching resolver (such as unbound) and pointing libc at it (by setting "nameserver 127.0.0.1" in your resolv.conf). Rather than having libc contacting some remote resolver (like your ISP), it'll now contact your local resolver. Having to set up a local resolver just to get secure SSHFP records is rather cumbersome. Perhaps the long-term solution is to link ssh against libunbound or libldns so that it resolves secure SSHFP records directly. In conclusion, Debian won't be using the x509-like PKI infrastructure for the above stated reasons. If you trust your resolver (install unbound!), you can use our SSHFP records to achieve what you want. Let me know if you have questions or comments, Luca -- Luca Filipozzi Member, Debian System Administration Team
diff -ru openssh-5.9p1/openbsd-compat/getrrsetbyname.c openssh-5.9p1-new/openbsd-compat/getrrsetbyname.c --- openssh-5.9p1/openbsd-compat/getrrsetbyname.c 2009-07-12 18:38:23.000000000 -0700 +++ openssh-5.9p1-new/openbsd-compat/getrrsetbyname.c 2012-05-08 10:24:12.000000000 -0700 @@ -45,6 +45,7 @@ /* OPENBSD ORIGINAL: lib/libc/net/getrrsetbyname.c */ +#include <unbound.h> #include "includes.h" #ifndef HAVE_GETRRSETBYNAME @@ -195,7 +196,8 @@ struct rdatainfo *rdata; int length; unsigned int index_ans, index_sig; - u_char answer[ANSWER_BUFFER_SIZE]; + struct ub_ctx *ub_ctx = NULL; + struct ub_result *ub_result; /* check for invalid class and type */ if (rdclass > 0xffff || rdtype > 0xffff) { @@ -215,41 +217,37 @@ goto fail; } - /* initialize resolver */ - if ((_resp->options & RES_INIT) == 0 && res_init() == -1) { + /* create context */ + ub_ctx = ub_ctx_create(); + if (!ub_ctx) { result = ERRSET_FAIL; goto fail; } -#ifdef DEBUG - _resp->options |= RES_DEBUG; -#endif /* DEBUG */ - -#ifdef RES_USE_DNSSEC - /* turn on DNSSEC if EDNS0 is configured */ - if (_resp->options & RES_USE_EDNS0) - _resp->options |= RES_USE_DNSSEC; -#endif /* RES_USE_DNSEC */ - - /* make query */ - length = res_query(hostname, (signed int) rdclass, (signed int) rdtype, - answer, sizeof(answer)); - if (length < 0) { - switch(h_errno) { - case HOST_NOT_FOUND: - result = ERRSET_NONAME; - goto fail; - case NO_DATA: - result = ERRSET_NODATA; - goto fail; - default: - result = ERRSET_FAIL; - goto fail; - } + /* load unbound configuration : FIXME - filename */ + if ((result = ub_ctx_config(ub_ctx, "/opt/local/etc/unbound/unbound.conf")) != 0) { + result = ERRSET_FAIL; + goto fail; + } + + /* execute query */ + if ((result = ub_resolve(ub_ctx, (char*)hostname, rdtype, rdclass, &ub_result)) != 0) { + result = ERRSET_FAIL; + goto fail; + } + + if (ub_result->nxdomain) { + result = ERRSET_NONAME; + goto fail; + } + + if (!ub_result->havedata) { + result = ERRSET_NODATA; + goto fail; } /* parse result */ - response = parse_dns_response(answer, length); + response = parse_dns_response(ub_result->answer_packet, ub_result->answer_len); if (response == NULL) { result = ERRSET_FAIL; goto fail; @@ -333,6 +331,8 @@ } } free_dns_response(response); + ub_resolve_free(ub_result); + ub_ctx_delete(ub_ctx); *res = rrset; return (ERRSET_SUCCESS); @@ -342,6 +342,10 @@ freerrset(rrset); if (response != NULL) free_dns_response(response); + if (ub_result != NULL) + ub_resolve_free(ub_result); + if (ub_ctx != NULL) + ub_ctx_delete(ub_ctx); return (result); }
Attachment:
signature.asc
Description: Digital signature