Phreebird
Phreebird is a DNSSEC proxy that operates in front of an existing DNS server (such as BIND, Unbound, PowerDNS, Microsoft DNS, or QIP) and supplements its records with DNSSEC responses. Features of Phreebird include automatic key generation, realtime record signing, support for arbitrary responses, zero configuration, NSEC3 “White Lies”, caching and rate limiting to deter DoS attacks, and experimental support for both Coarse Time over DNS and HTTP Virtual Channels. The suite also contains a large amount of sample code, including support for federated identity over OpenSSH. Finally, “Phreeload” enhances existing OpenSSL applications with DNSSEC support.
Download: Phreebird Suite 1.02
Thank you Dan for making this available.
I have deployed KEY1 on mattmccutchen.net.
There seems to be a gap in the security of phreeload: it checks for KEY1 at the certificate’s common name, but OpenSSL-based applications will also accept the certificate for its subjectAltNames. Unfortunately, the way the OpenSSL API is designed, there is no single X509_verify_cert_for_host function that phreeload could override to supply the right semantics. That functionality is generally only brought together in application protocol implementations such as libcurl and libsoup. You could consider patching some of those instead.
Matt,
Glad to hear from you. The case you refer to should be handled by the fact that, if one of the SAN names is browsed to, there will be a message of authoritative nonexistence for that domain. Then, I’ll fail over to the existing x509_verify_cert, which will catch the SAN.
Alternatively, you can push KEY1 to both the normal domain and the SAN domain, and do everything in DNSSEC.
Suppose I generate a certificate with CN = mattmccutchen.net, SAN = dankaminsky.com and post the corresponding KEY1 at mattmccutchen.net. You try to connect to dankaminsky.com with phreeload, and I intercept the connection and present my certificate. Phreeload queries DNSSEC at the CN and sees my KEY1, so you accept the certificate. What am I missing?
Matt–
Oh yeah, I forgot. The API sucks right now; Phreeload doesn’t know at the moment that this was a connection attempt to mattmccutchen.net, so it only checks the domain in the CN, not the SAN. It’s safe, because of the assumption that something else later will check CN.
I’ll add parallel SAN support to 1.03.
I say the API sucks because x509_verify_cert doesn’t actually know the name to compare against.
Not a good assumption. Almost all clients check the SAN.
What does that mean? Phreeload would check for KEY1 at all of the names in the SAN? That would be slow, but maybe server operators would adapt by not using certificates with many names. What if the SAN contains *.foo.com? Even if there is a KEY1 at *.foo.com (a DNS wildcard), strictly speaking, you still need to know it hasn’t been overridden at somesub.foo.com, and there is no way to test all possible subdomains.
Of course it doesn’t, that’s not a defect. The defect is that determination of cert acceptability for a server name (which is what Phreeload needs to replace) is not encapsulated in a single function in any of the major open source SSL/TLS libraries. NSS and GnuTLS make applications call one function for X509 verification and another for a name check, while OpenSSL makes applications implement the name check themselves (way to get bugs!).
The “proper” solution would be to add better API to the libraries and port applications to use it. In the meantime, replacing ssl_verify_cert_chain and using the tlsext_hostname may work for most SNI clients. Alternatively, one could use Phoxie. Do you plan to release it to the public?
CryptoAPI also follows the OpenSSL model, and yes, way to get bugs.
I thought I had some reason that API wouldn’t work. Specifically, the name checking functionality just wasn’t there. Could be wrong though.
It’s super sketchy python right now. Interested in helping me make a solid C port?
The OpenSSL function does not do a name check, but your replacement can. That will ensure that KEY1 endorsement, when applicable, is a necessary condition for a cert to be accepted. The application may do additional name checking, but that just means the admin has to use a cert containing the appropriate names, which is generally easy to arrange. If you take this approach, then the complexity of having to check all the SANs goes away.
It’s super sketchy python right now. Interested in helping me make a solid C port?
Interested, but unlikely to actually find the time. I’d encourage you to go ahead and release what you have so people can start playing with it.
In keeping with your goal of easy deployment, have you thought about making Phreebird automatically generate KEY1 records:
from the cert presented by the host, if the organization is confident in the security of their internal network
after verifying the presented cert against an existing X.509 CA operated by the organization?
Does phreebird support ipv6?
And can I support multiple views or will I have to have two phreebird processes with the same key?
Correction: NSS has such a function, SSL_AuthCertificate.
I have made a proof-of-concept DANE implementation for NSS by modifying SSL_AuthCertificate. The DNSSEC is done with libunbound, inspired by Phreeload.