diff options
Diffstat (limited to 'third_party/dnspython/dns/dnssec.py')
-rw-r--r-- | third_party/dnspython/dns/dnssec.py | 372 |
1 files changed, 0 insertions, 372 deletions
diff --git a/third_party/dnspython/dns/dnssec.py b/third_party/dnspython/dns/dnssec.py deleted file mode 100644 index 85ea170eafa..00000000000 --- a/third_party/dnspython/dns/dnssec.py +++ /dev/null @@ -1,372 +0,0 @@ -# Copyright (C) 2003-2007, 2009, 2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Common DNSSEC-related functions and constants.""" - -import cStringIO -import struct -import time - -import dns.exception -import dns.hash -import dns.name -import dns.node -import dns.rdataset -import dns.rdata -import dns.rdatatype -import dns.rdataclass - -class UnsupportedAlgorithm(dns.exception.DNSException): - """Raised if an algorithm is not supported.""" - pass - -class ValidationFailure(dns.exception.DNSException): - """The DNSSEC signature is invalid.""" - pass - -RSAMD5 = 1 -DH = 2 -DSA = 3 -ECC = 4 -RSASHA1 = 5 -DSANSEC3SHA1 = 6 -RSASHA1NSEC3SHA1 = 7 -RSASHA256 = 8 -RSASHA512 = 10 -INDIRECT = 252 -PRIVATEDNS = 253 -PRIVATEOID = 254 - -_algorithm_by_text = { - 'RSAMD5' : RSAMD5, - 'DH' : DH, - 'DSA' : DSA, - 'ECC' : ECC, - 'RSASHA1' : RSASHA1, - 'DSANSEC3SHA1' : DSANSEC3SHA1, - 'RSASHA1NSEC3SHA1' : RSASHA1NSEC3SHA1, - 'RSASHA256' : RSASHA256, - 'RSASHA512' : RSASHA512, - 'INDIRECT' : INDIRECT, - 'PRIVATEDNS' : PRIVATEDNS, - 'PRIVATEOID' : PRIVATEOID, - } - -# We construct the inverse mapping programmatically to ensure that we -# cannot make any mistakes (e.g. omissions, cut-and-paste errors) that -# would cause the mapping not to be true inverse. - -_algorithm_by_value = dict([(y, x) for x, y in _algorithm_by_text.iteritems()]) - -def algorithm_from_text(text): - """Convert text into a DNSSEC algorithm value - @rtype: int""" - - value = _algorithm_by_text.get(text.upper()) - if value is None: - value = int(text) - return value - -def algorithm_to_text(value): - """Convert a DNSSEC algorithm value to text - @rtype: string""" - - text = _algorithm_by_value.get(value) - if text is None: - text = str(value) - return text - -def _to_rdata(record, origin): - s = cStringIO.StringIO() - record.to_wire(s, origin=origin) - return s.getvalue() - -def key_id(key, origin=None): - rdata = _to_rdata(key, origin) - if key.algorithm == RSAMD5: - return (ord(rdata[-3]) << 8) + ord(rdata[-2]) - else: - total = 0 - for i in range(len(rdata) // 2): - total += (ord(rdata[2 * i]) << 8) + ord(rdata[2 * i + 1]) - if len(rdata) % 2 != 0: - total += ord(rdata[len(rdata) - 1]) << 8 - total += ((total >> 16) & 0xffff); - return total & 0xffff - -def make_ds(name, key, algorithm, origin=None): - if algorithm.upper() == 'SHA1': - dsalg = 1 - hash = dns.hash.get('SHA1')() - elif algorithm.upper() == 'SHA256': - dsalg = 2 - hash = dns.hash.get('SHA256')() - else: - raise UnsupportedAlgorithm, 'unsupported algorithm "%s"' % algorithm - - if isinstance(name, (str, unicode)): - name = dns.name.from_text(name, origin) - hash.update(name.canonicalize().to_wire()) - hash.update(_to_rdata(key, origin)) - digest = hash.digest() - - dsrdata = struct.pack("!HBB", key_id(key), key.algorithm, dsalg) + digest - return dns.rdata.from_wire(dns.rdataclass.IN, dns.rdatatype.DS, dsrdata, 0, - len(dsrdata)) - -def _find_key(keys, rrsig): - value = keys.get(rrsig.signer) - if value is None: - return None - if isinstance(value, dns.node.Node): - try: - rdataset = value.find_rdataset(dns.rdataclass.IN, - dns.rdatatype.DNSKEY) - except KeyError: - return None - else: - rdataset = value - for rdata in rdataset: - if rdata.algorithm == rrsig.algorithm and \ - key_id(rdata) == rrsig.key_tag: - return rdata - return None - -def _is_rsa(algorithm): - return algorithm in (RSAMD5, RSASHA1, - RSASHA1NSEC3SHA1, RSASHA256, - RSASHA512) - -def _is_dsa(algorithm): - return algorithm in (DSA, DSANSEC3SHA1) - -def _is_md5(algorithm): - return algorithm == RSAMD5 - -def _is_sha1(algorithm): - return algorithm in (DSA, RSASHA1, - DSANSEC3SHA1, RSASHA1NSEC3SHA1) - -def _is_sha256(algorithm): - return algorithm == RSASHA256 - -def _is_sha512(algorithm): - return algorithm == RSASHA512 - -def _make_hash(algorithm): - if _is_md5(algorithm): - return dns.hash.get('MD5')() - if _is_sha1(algorithm): - return dns.hash.get('SHA1')() - if _is_sha256(algorithm): - return dns.hash.get('SHA256')() - if _is_sha512(algorithm): - return dns.hash.get('SHA512')() - raise ValidationFailure, 'unknown hash for algorithm %u' % algorithm - -def _make_algorithm_id(algorithm): - if _is_md5(algorithm): - oid = [0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05] - elif _is_sha1(algorithm): - oid = [0x2b, 0x0e, 0x03, 0x02, 0x1a] - elif _is_sha256(algorithm): - oid = [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01] - elif _is_sha512(algorithm): - oid = [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03] - else: - raise ValidationFailure, 'unknown algorithm %u' % algorithm - olen = len(oid) - dlen = _make_hash(algorithm).digest_size - idbytes = [0x30] + [8 + olen + dlen] + \ - [0x30, olen + 4] + [0x06, olen] + oid + \ - [0x05, 0x00] + [0x04, dlen] - return ''.join(map(chr, idbytes)) - -def _validate_rrsig(rrset, rrsig, keys, origin=None, now=None): - """Validate an RRset against a single signature rdata - - The owner name of the rrsig is assumed to be the same as the owner name - of the rrset. - - @param rrset: The RRset to validate - @type rrset: dns.rrset.RRset or (dns.name.Name, dns.rdataset.Rdataset) - tuple - @param rrsig: The signature rdata - @type rrsig: dns.rrset.Rdata - @param keys: The key dictionary. - @type keys: a dictionary keyed by dns.name.Name with node or rdataset values - @param origin: The origin to use for relative names - @type origin: dns.name.Name or None - @param now: The time to use when validating the signatures. The default - is the current time. - @type now: int - """ - - if isinstance(origin, (str, unicode)): - origin = dns.name.from_text(origin, dns.name.root) - - key = _find_key(keys, rrsig) - if not key: - raise ValidationFailure, 'unknown key' - - # For convenience, allow the rrset to be specified as a (name, rdataset) - # tuple as well as a proper rrset - if isinstance(rrset, tuple): - rrname = rrset[0] - rdataset = rrset[1] - else: - rrname = rrset.name - rdataset = rrset - - if now is None: - now = time.time() - if rrsig.expiration < now: - raise ValidationFailure, 'expired' - if rrsig.inception > now: - raise ValidationFailure, 'not yet valid' - - hash = _make_hash(rrsig.algorithm) - - if _is_rsa(rrsig.algorithm): - keyptr = key.key - (bytes,) = struct.unpack('!B', keyptr[0:1]) - keyptr = keyptr[1:] - if bytes == 0: - (bytes,) = struct.unpack('!H', keyptr[0:2]) - keyptr = keyptr[2:] - rsa_e = keyptr[0:bytes] - rsa_n = keyptr[bytes:] - keylen = len(rsa_n) * 8 - pubkey = Crypto.PublicKey.RSA.construct( - (Crypto.Util.number.bytes_to_long(rsa_n), - Crypto.Util.number.bytes_to_long(rsa_e))) - sig = (Crypto.Util.number.bytes_to_long(rrsig.signature),) - elif _is_dsa(rrsig.algorithm): - keyptr = key.key - (t,) = struct.unpack('!B', keyptr[0:1]) - keyptr = keyptr[1:] - octets = 64 + t * 8 - dsa_q = keyptr[0:20] - keyptr = keyptr[20:] - dsa_p = keyptr[0:octets] - keyptr = keyptr[octets:] - dsa_g = keyptr[0:octets] - keyptr = keyptr[octets:] - dsa_y = keyptr[0:octets] - pubkey = Crypto.PublicKey.DSA.construct( - (Crypto.Util.number.bytes_to_long(dsa_y), - Crypto.Util.number.bytes_to_long(dsa_g), - Crypto.Util.number.bytes_to_long(dsa_p), - Crypto.Util.number.bytes_to_long(dsa_q))) - (dsa_r, dsa_s) = struct.unpack('!20s20s', rrsig.signature[1:]) - sig = (Crypto.Util.number.bytes_to_long(dsa_r), - Crypto.Util.number.bytes_to_long(dsa_s)) - else: - raise ValidationFailure, 'unknown algorithm %u' % rrsig.algorithm - - hash.update(_to_rdata(rrsig, origin)[:18]) - hash.update(rrsig.signer.to_digestable(origin)) - - if rrsig.labels < len(rrname) - 1: - suffix = rrname.split(rrsig.labels + 1)[1] - rrname = dns.name.from_text('*', suffix) - rrnamebuf = rrname.to_digestable(origin) - rrfixed = struct.pack('!HHI', rdataset.rdtype, rdataset.rdclass, - rrsig.original_ttl) - rrlist = sorted(rdataset); - for rr in rrlist: - hash.update(rrnamebuf) - hash.update(rrfixed) - rrdata = rr.to_digestable(origin) - rrlen = struct.pack('!H', len(rrdata)) - hash.update(rrlen) - hash.update(rrdata) - - digest = hash.digest() - - if _is_rsa(rrsig.algorithm): - # PKCS1 algorithm identifier goop - digest = _make_algorithm_id(rrsig.algorithm) + digest - padlen = keylen // 8 - len(digest) - 3 - digest = chr(0) + chr(1) + chr(0xFF) * padlen + chr(0) + digest - elif _is_dsa(rrsig.algorithm): - pass - else: - # Raise here for code clarity; this won't actually ever happen - # since if the algorithm is really unknown we'd already have - # raised an exception above - raise ValidationFailure, 'unknown algorithm %u' % rrsig.algorithm - - if not pubkey.verify(digest, sig): - raise ValidationFailure, 'verify failure' - -def _validate(rrset, rrsigset, keys, origin=None, now=None): - """Validate an RRset - - @param rrset: The RRset to validate - @type rrset: dns.rrset.RRset or (dns.name.Name, dns.rdataset.Rdataset) - tuple - @param rrsigset: The signature RRset - @type rrsigset: dns.rrset.RRset or (dns.name.Name, dns.rdataset.Rdataset) - tuple - @param keys: The key dictionary. - @type keys: a dictionary keyed by dns.name.Name with node or rdataset values - @param origin: The origin to use for relative names - @type origin: dns.name.Name or None - @param now: The time to use when validating the signatures. The default - is the current time. - @type now: int - """ - - if isinstance(origin, (str, unicode)): - origin = dns.name.from_text(origin, dns.name.root) - - if isinstance(rrset, tuple): - rrname = rrset[0] - else: - rrname = rrset.name - - if isinstance(rrsigset, tuple): - rrsigname = rrsigset[0] - rrsigrdataset = rrsigset[1] - else: - rrsigname = rrsigset.name - rrsigrdataset = rrsigset - - rrname = rrname.choose_relativity(origin) - rrsigname = rrname.choose_relativity(origin) - if rrname != rrsigname: - raise ValidationFailure, "owner names do not match" - - for rrsig in rrsigrdataset: - try: - _validate_rrsig(rrset, rrsig, keys, origin, now) - return - except ValidationFailure, e: - pass - raise ValidationFailure, "no RRSIGs validated" - -def _need_pycrypto(*args, **kwargs): - raise NotImplementedError, "DNSSEC validation requires pycrypto" - -try: - import Crypto.PublicKey.RSA - import Crypto.PublicKey.DSA - import Crypto.Util.number - validate = _validate - validate_rrsig = _validate_rrsig -except ImportError: - validate = _need_pycrypto - validate_rrsig = _need_pycrypto |