ADVANCED DNS SERVICES:	
APPLICATION SECURITY AND USER PRIVACY
PyCon 2016	
Melinda Shore	
melinda.shore@nomountain.net
GETDNS
• new DNS library, supporting new DNS protocol features	
• one-step DNSSEC validation	
• C library asynchronous by default, Python module has
optional callback argument to queries	
• transport options to protect user privacy, avoid
middlebox woes
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
CHANGES IN NETWORK
PLUMBING
• changes in network protocols can make
application developers’ lives easier	
• here’s how
5-MINUTE DNSTUTORIAL
• stateless query-response protocol	
• send a query to your DNS server, it returns your
query along with a set of answers	
• DNS resource records
DNS STRUCTURE
• Distributed database	
• Hierarchical
DNS STRUCTURE
.
.org.com .uk .biz .reisen
ietf effpython isoc
mail pypi www
root zone
TLDs
second-level	
domains
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$
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
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. 417IN A 185.49.141.37
getdnsapi.net. 417IN 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
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$
A NEWTRUST MODEL FOR
THE INTERNET
Hey, this thing securely serves up public
keys!
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
PKI ISSUES
• certificate “misissuance”	
• TurkTrust, for example	
• careless key usage constraints — people posing as
CAs and issuing certs	
• compromised CAs
BLUE COAT
• Blue Coat makes network intermediaries that enable censorship and user
surveillance	
• Identified in 2013 Reporters Without Borders report as an “Enemy of the Internet”	
• customers include Syria, Iran, China, other countries known to censor access and
have broad-based surveillance programs	
• Symantec issued a CA cert to Blue Coat	
• Blue Coat says they will not be using it, but the problem stands: an intermediary that
can issue certificates that chain back to a reputable trust source can transparently
MITM network traffic
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
DANE
• to authenticateTLS servers, retrieve aTLSA
record from the DNS	
• make sure its signature checks out	
• compare the certificate in theTLSA record with
the one presented in theTLS server_hello
RETRIEVETHETLSA RECORD
ctx = getdns.Context()
results = ctx.general(name=qname,
request_type=getdns.RRTYPE_TLSA,
extensions=extensions)
GETTHE SERVER CERT
connection = SSL.Connection(sslctx, sock=sock)
connection.connect((ipaddr, port))
chain = connection.get_peer_cert_chain()
cert = chain[0]
PULL DATA OUT OFTHE
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
COMPARE WHATYOU’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
GETDNS AND DANE
• Sample code: https://raw.githubusercontent.com/
getdnsapi/getdns-python-bindings/master/
examples/checkdanecert.py
OTHER DANE APPLICATIONS
• openpgp keys	
• S/MIME keys	
• use ofTLSA records to protect SMTP sessions
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 certificate was stored in aTLSA
record
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
PRIVACY PROTECTION
• TLS transport: 

context.dns_transport_list =
[ getdns.TRANSPORT_TLS ]
• Padding: 

context.tls_query_padding_blocksize = 256
“ROADBLOCK”AVOIDANCE
• Middleboxes (firewalls, NATs, other stateful
transport intermediaries) sometimes filter out
DNS traffic they misidentify as malicious	
• The underlying getdns library detects these and
works around them
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
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/
JOIN OUR MAILING LIST
• http://getdnsapi.org/mailman/listinfo/users
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 forTwisted, a DANE
API, or your excellent idea	
• http://ietf.org/hackathon/96-hackathon.html
@MelindaShore

getdns PyCon presentation

  • 1.
    ADVANCED DNS SERVICES: APPLICATIONSECURITY AND USER PRIVACY PyCon 2016 Melinda Shore melinda.shore@nomountain.net
  • 2.
    GETDNS • new DNSlibrary, supporting new DNS protocol features • one-step DNSSEC validation • C library asynchronous by default, Python module has optional callback argument to queries • transport options to protect user privacy, avoid middlebox woes
  • 3.
    GETDNS • Original specificationwas 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
  • 4.
    CHANGES IN NETWORK PLUMBING •changes in network protocols can make application developers’ lives easier • here’s how
  • 5.
    5-MINUTE DNSTUTORIAL • statelessquery-response protocol • send a query to your DNS server, it returns your query along with a set of answers • DNS resource records
  • 6.
    DNS STRUCTURE • Distributeddatabase • Hierarchical
  • 7.
    DNS STRUCTURE . .org.com .uk.biz .reisen ietf effpython isoc mail pypi www root zone TLDs second-level domains
  • 8.
    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$
  • 9.
    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
  • 10.
    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. 417IN A 185.49.141.37 getdnsapi.net. 417IN 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
  • 11.
    ENTER GETDNS shore@birch:~/src/tmp$ catsimple.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$
  • 12.
    A NEWTRUST MODELFOR THE INTERNET Hey, this thing securely serves up public keys!
  • 13.
    PKI • You’ve gotto 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
  • 14.
    PKI ISSUES • certificate“misissuance” • TurkTrust, for example • careless key usage constraints — people posing as CAs and issuing certs • compromised CAs
  • 15.
    BLUE COAT • BlueCoat makes network intermediaries that enable censorship and user surveillance • Identified in 2013 Reporters Without Borders report as an “Enemy of the Internet” • customers include Syria, Iran, China, other countries known to censor access and have broad-based surveillance programs • Symantec issued a CA cert to Blue Coat • Blue Coat says they will not be using it, but the problem stands: an intermediary that can issue certificates that chain back to a reputable trust source can transparently MITM network traffic
  • 16.
    DANE • DNS-Based Authenticationof 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
  • 17.
    DANE • to authenticateTLSservers, retrieve aTLSA record from the DNS • make sure its signature checks out • compare the certificate in theTLSA record with the one presented in theTLS server_hello
  • 18.
    RETRIEVETHETLSA RECORD ctx =getdns.Context() results = ctx.general(name=qname, request_type=getdns.RRTYPE_TLSA, extensions=extensions)
  • 19.
    GETTHE SERVER CERT connection= SSL.Connection(sslctx, sock=sock) connection.connect((ipaddr, port)) chain = connection.get_peer_cert_chain() cert = chain[0]
  • 20.
    PULL DATA OUTOFTHE 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
  • 21.
    COMPARE WHATYOU’VE GOT defverify_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
  • 22.
    GETDNS AND DANE •Sample code: https://raw.githubusercontent.com/ getdnsapi/getdns-python-bindings/master/ examples/checkdanecert.py
  • 23.
    OTHER DANE APPLICATIONS •openpgp keys • S/MIME keys • use ofTLSA records to protect SMTP sessions
  • 24.
    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 certificate was stored in aTLSA record
  • 25.
    DNS PRIVACY • IETFRFC 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
  • 26.
    PRIVACY PROTECTION • TLStransport: 
 context.dns_transport_list = [ getdns.TRANSPORT_TLS ] • Padding: 
 context.tls_query_padding_blocksize = 256
  • 27.
    “ROADBLOCK”AVOIDANCE • Middleboxes (firewalls,NATs, other stateful transport intermediaries) sometimes filter out DNS traffic they misidentify as malicious • The underlying getdns library detects these and works around them
  • 28.
    STATUS • Now feature-completewith respect to the original spec • Ongoing integration of new protocol features • Python bindings have been very useful for quick prototyping
  • 29.
    FIND US! • Projecthome 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/
  • 30.
    JOIN OUR MAILINGLIST • http://getdnsapi.org/mailman/listinfo/users
  • 31.
    UPCOMING HACKATHON • IETF96 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 forTwisted, a DANE API, or your excellent idea • http://ietf.org/hackathon/96-hackathon.html
  • 32.