Slide 1

Slide 1 text

ADVANCED DNS SERVICES: APPLICATION SECURITY AND USER PRIVACY PyCon 2016 Melinda Shore melinda.shore@nomountain.net

Slide 2

Slide 2 text

GETDNS • new DNS library • one-step DNSSEC validation • transport options to protect user privacy, avoid middlebox woes

Slide 3

Slide 3 text

GETDNS • Original specification was for a C API, actually fits Python and other modern languages somewhat better (data structures) • Language bindings: Python, node.js, PHP. Ruby is under development. • Hackathons: TNW, IETF. Won “Best Internet Security Improvement” at IETF 94 hackathon in November

Slide 4

Slide 4 text

PLUMBING HAPPENS • changes in network protocols can make application developers’ lives easier • here’s how

Slide 5

Slide 5 text

5-MINUTE DNS TUTORIAL • stateless query-response protocol • send a query to your DNS server, it returns your query along with a set of answers • DNS resource records

Slide 6

Slide 6 text

DNS STRUCTURE • Distributed database • Hierarchical

Slide 7

Slide 7 text

DNS STRUCTURE . .org .com .uk .biz .reisen ietf eff python isoc mail pypi www root zone TLDs second-level domains

Slide 8

Slide 8 text

DIG EXAMPLE Melindas-MacBook-Pro:~ melinda$ which dig /usr/bin/dig Melindas-MacBook-Pro:~ melinda$ dig getdnsapi.net a ! ; <<>> DiG 9.8.3-P1 <<>> getdnsapi.net a ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1925 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ! ;; QUESTION SECTION: ;getdnsapi.net. IN A ! ;; ANSWER SECTION: getdnsapi.net. 449 IN A 185.49.141.37 ! ;; Query time: 244 msec ;; SERVER: 8.8.8.8#53(8.8.8.8) ;; WHEN: Thu May 26 20:06:01 2016 ;; MSG SIZE rcvd: 47 ! Melindas-MacBook-Pro:~ melinda$

Slide 9

Slide 9 text

DNSSEC • The problem: it’s easy to forge DNS packets, with obvious consequences (AKA “Kaminsky attack,” after Dan Kaminsky) • DNSSEC is a mechanism to prove the authenticity of a DNS record • The trust model: hierarchy of signed records chaining up to the DNS root zone

Slide 10

Slide 10 text

DNSSEC EXAMPLE Melindas-MacBook-Pro:src melinda$ dig +dnssec getdnsapi.net a ! ; <<>> DiG 9.8.3-P1 <<>> +dnssec getdnsapi.net a ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 27162 ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1 ! ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags: do; udp: 512 ;; QUESTION SECTION: ;getdnsapi.net. IN A ! ;; ANSWER SECTION: getdnsapi.net. 417 IN A 185.49.141.37 getdnsapi.net. 417 IN RRSIG A 7 2 450 20160608170833 20160518143030 23885 getdnsapi.net. bDcGGokWnupa9khd8rhr0SbjUEXHFmCpUWlbkNeXZx/Ugy90eWvpcY72 H2LWale/2CP5Q4V/+M0XMnEakkZOFBA3h58n/8pGK3MuSHthX/ E0CD1b DFvCgfeLxyFde5RoIpZ6Mx0SVG5/3A/Lc2Yn56MUcBecLKHBNLqv+oux /Ys= ! ;; Query time: 133 msec ;; SERVER: 8.8.8.8#53(8.8.8.8) ;; WHEN: Thu May 26 21:47:11 2016 ;; MSG SIZE rcvd: 231

Slide 11

Slide 11 text

ENTER GETDNS shore@birch:~/src/tmp$ cat simple.py import getdns, sys ! context = getdns.Context() ext = { 'dnssec_return_only_secure': getdns.EXTENSION_TRUE } r = context.address(sys.argv[1], extensions=ext) if r.status == getdns.RESPSTATUS_GOOD: for addr in r.just_address_answers: print(addr['address_data']) if r.status == getdns.RESPSTATUS_NO_SECURE_ANSWERS: print("No secure answers”) ! shore@birch:~/src/tmp$ python simple.py getdnsapi.net 2a04:b900:0:100::37 185.49.141.37 ! shore@birch:~/src/tmp$ python simple.py google.com No secure answers shore@birch:~/src/tmp$

Slide 12

Slide 12 text

A NEW TRUST MODEL FOR THE INTERNET Hey, this thing securely serves up public keys!

Slide 13

Slide 13 text

PKI • You’ve got to trust somebody • the public key infrastructure is also based on a hierarchy of credentials chaining back to a root • browser vendors end up making decisions about what goes in the root trust store • That hasn’t always worked out well

Slide 14

Slide 14 text

PKI ISSUES • certificate “misissuance” • careless key usage constraints — people posing as CAs and issuing certs • compromised CAs

Slide 15

Slide 15 text

DANE • DNS-Based Authentication of Named Entities • Here’s the idea: move trust management and credential validation closer to an organization’s own infrastructure • Here’s the implementation: put public key credentials in the DNS, protected by DNSSEC

Slide 16

Slide 16 text

DANE • to authenticate TLS servers, retrieve a TLSA record from the DNS • make sure its signature checks out • compare the certificate in the TLSA record with the one presented in the TLS server_hello

Slide 17

Slide 17 text

RETRIEVE THE TLSA RECORD ctx = getdns.Context() try: results = ctx.general(name=qname, request_type=getdns.RRTYPE_TLSA, extensions=extensions)

Slide 18

Slide 18 text

GET THE SERVER CERT connection = SSL.Connection(sslctx, sock=sock) connection.connect((ipaddr, port)) chain = connection.get_peer_cert_chain() cert = chain[0]

Slide 19

Slide 19 text

PULL DATA OUT OF THE RECORD def get_tlsa_rdata_set(replies, requested_usage=None): tlsa_rdata_set = [] for reply in replies: for rr in reply['answer']: if rr['type'] == getdns.RRTYPE_TLSA: rdata = rr['rdata'] usage = rdata['certificate_usage'] selector = rdata['selector'] matching_type = rdata['matching_type'] cadata = rdata['certificate_association_data'] cadata = str(cadata).encode('hex') if usage == requested_usage: tlsa_rdata_set.append( (usage, selector, matching_type, cadata) ) return tlsa_rdata_set

Slide 20

Slide 20 text

COMPARE WHAT YOU’VE GOT def verify_tlsa(cert, usage, selector, matchtype, hexdata1): ! if selector == 0: certdata = cert.as_der() elif selector == 1: certdata = cert.get_pubkey().as_der() else: raise ValueError("selector type %d not recognized" % selector) ! if matchtype == 0: hexdata2 = hexdump(certdata) elif matchtype == 1: hexdata2 = compute_hash(hashlib.sha256, certdata) elif matchtype == 2: hexdata2 = compute_hash(hashlib.sha512, certdata) else: raise ValueError("matchtype %d not recognized" % matchtype) ! if hexdata1 == hexdata2: return True else: return False

Slide 21

Slide 21 text

GETDNS AND DANE • Sample code: https://raw.githubusercontent.com/ getdnsapi/getdns-python-bindings/master/ examples/checkdanecert.py

Slide 22

Slide 22 text

OTHER DANE APPLICATIONS • openpgp keys • S/MIME keys • use of TLSA records to protect SMTP sessions

Slide 23

Slide 23 text

ENCRYPTION EXAMPLE • https://raw.githubusercontent.com/getdnsapi/ getdns-python-bindings/master/examples/ dane_encrypt.py • This was written quite early in the DANE process, and the S/MIME key was stored as a TLSA record

Slide 24

Slide 24 text

DNS PRIVACY • IETF RFC 7258: “Pervasive monitoring is a technical attack that should be mitigated in the design of IETF protocols, where possible.” • DNS leaks a massive amount of information about what a user is doing on the network

Slide 25

Slide 25 text

PRIVACY PROTECTION • TLS transport: 
 context.dns_transport_list = [ getdns.TRANSPORT_TLS ] • Padding: 
 context.tls_query_padding_blocksize = 256

Slide 26

Slide 26 text

“ROADBLOCK” AVOIDANCE • Middleboxes (firewalls, NATs, other stateful transport intermediaries) sometimes filter out DNS traffic it misidentifies as malicious • The underlying getdns library detects these and works around them

Slide 27

Slide 27 text

STATUS • Now feature-complete with respect to the original spec • Ongoing integration of new protocol features • Python bindings have been very useful for quick prototyping

Slide 28

Slide 28 text

FIND US! • Project home page: https://getdnsapi.net • Github: https://github.com/getdnsapi • PyPI: https://pypi.python.org/pypi/getdns/v1.0.0b1 • Documentation: http://getdns.readthedocs.org/ • Docker image: https://hub.docker.com/r/melindashore/ getdns-python2/

Slide 29

Slide 29 text

JOIN OUR MAILING LIST • http://getdnsapi.org/mailman/listinfo/users

Slide 30

Slide 30 text

UPCOMING HACKATHON • IETF 96 Hackathon, Berlin, Germany • Intercontinental Hotel, July 16/17, 2016 • You do not need to be registered for or participating in the IETF meeting • Potential projects include: a getdns protocol for Twisted, a DANE API, or your excellent idea • http://ietf.org/hackathon/96-hackathon.html

Slide 31

Slide 31 text

Questions?