RSASHA1NSEC3SHA1 = 7
RSASHA256 = 8
RSASHA512 = 10
+ECDSAP256SHA256 = 13
+ECDSAP384SHA384 = 14
INDIRECT = 252
PRIVATEDNS = 253
PRIVATEOID = 254
'RSASHA256' : RSASHA256,
'RSASHA512' : RSASHA512,
'INDIRECT' : INDIRECT,
+ 'ECDSAP256SHA256' : ECDSAP256SHA256,
+ 'ECDSAP384SHA384' : ECDSAP384SHA384,
'PRIVATEDNS' : PRIVATEDNS,
'PRIVATEOID' : PRIVATEOID,
}
def _is_dsa(algorithm):
return algorithm in (DSA, DSANSEC3SHA1)
+def _is_ecdsa(algorithm):
+ return _have_ecdsa and (algorithm in (ECDSAP256SHA256, ECDSAP384SHA384))
+
def _is_md5(algorithm):
return algorithm == RSAMD5
DSANSEC3SHA1, RSASHA1NSEC3SHA1)
def _is_sha256(algorithm):
- return algorithm == RSASHA256
+ return algorithm in (RSASHA256, ECDSAP256SHA256)
+
+def _is_sha384(algorithm):
+ return algorithm == ECDSAP384SHA384
def _is_sha512(algorithm):
return algorithm == RSASHA512
return dns.hash.get('SHA1')()
if _is_sha256(algorithm):
return dns.hash.get('SHA256')()
+ if _is_sha384(algorithm):
+ return dns.hash.get('SHA384')()
if _is_sha512(algorithm):
return dns.hash.get('SHA512')()
raise ValidationFailure('unknown hash for algorithm %u' % algorithm)
(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))
+ elif _is_ecdsa(rrsig.algorithm):
+ if rrsig.algorithm == ECDSAP256SHA256:
+ curve = ecdsa.curves.NIST256p
+ key_len = 32
+ digest_len = 32
+ elif rrsig.algorithm == ECDSAP384SHA384:
+ curve = ecdsa.curves.NIST384p
+ key_len = 48
+ digest_len = 48
+ else:
+ # shouldn't happen
+ raise ValidationFailure('unknown ECDSA curve')
+ keyptr = candidate_key.key
+ x = Crypto.Util.number.bytes_to_long(keyptr[0:key_len])
+ y = Crypto.Util.number.bytes_to_long(keyptr[key_len:key_len * 2])
+ assert ecdsa.ecdsa.point_is_valid(curve.generator, x, y)
+ point = ecdsa.ellipticcurve.Point(curve.curve, x, y, curve.order)
+ verifying_key = ecdsa.keys.VerifyingKey.from_public_point(point,
+ curve)
+ pubkey = ECKeyWrapper(verifying_key, key_len)
+ r = rrsig.signature[:key_len]
+ s = rrsig.signature[key_len:]
+ sig = ecdsa.ecdsa.Signature(Crypto.Util.number.bytes_to_long(r),
+ Crypto.Util.number.bytes_to_long(s))
else:
raise ValidationFailure('unknown algorithm %u' % rrsig.algorithm)
padlen = keylen // 8 - len(digest) - 3
digest = bytes([0]) + bytes([1]) + bytes([0xFF]) * padlen + \
bytes([0]) + digest
- elif _is_dsa(rrsig.algorithm):
+ elif _is_dsa(rrsig.algorithm) or _is_ecdsa(rrsig.algorithm):
pass
else:
# Raise here for code clarity; this won't actually ever happen
validate = _need_pycrypto
validate_rrsig = _need_pycrypto
_have_pycrypto = False
+
+try:
+ import ecdsa
+ import ecdsa.ecdsa
+ import ecdsa.ellipticcurve
+ import ecdsa.keys
+ _have_ecdsa = True
+
+ class ECKeyWrapper(object):
+ def __init__(self, key, key_len):
+ self.key = key
+ self.key_len = key_len
+ def verify(self, digest, sig):
+ diglong = Crypto.Util.number.bytes_to_long(digest)
+ return self.key.pubkey.verifies(diglong, sig)
+
+except ImportError:
+ _have_ecdsa = False
example_ds_sha256 = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DS,
'18673 3 2 eb8344cbbf07c9d3d3d6c81d10c76653e28d8611a65e639ef8f716e4e4e5d913')
+when3 = 1379801800
+
+abs_ecdsa256_keys = { abs_example :
+ dns.rrset.from_text('example.', 86400, 'IN', 'DNSKEY',
+ "256 3 13 +3ss1sCpdARVA61DJigEsL/8quo2a8MszKtn2gkkfxgzFs8S2UHtpb4N fY+XFmNW+JK6MsCkI3jHYN8eEQUgMw==",
+ "257 3 13 eJCEVH7AS3wnoaQpaNlAXH0W8wxymtT9P6P3qjN2ZCV641ED8pF7wZ5V yWfOpgTs6oaZevbJgehl/GaRPUgVyQ==")
+ }
+
+abs_ecdsa256_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA',
+ 'ns1.example. hostmaster.example. 4 10800 3600 604800 86400')
+
+abs_other_ecdsa256_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA',
+ 'ns1.example. hostmaster.example. 2 10800 3600 604800 86401')
+
+abs_ecdsa256_soa_rrsig = dns.rrset.from_text('example.', 86400, 'IN', 'RRSIG',
+ "SOA 13 1 86400 20130921221753 20130921221638 7460 example. Sm09SOGz1ULB5D/duwdE2Zpn8bWbVBM77H6N1wPkc42LevvVO+kZEjpq 2nq4GOMJcih52667GIAbMrwmU5P2MQ==")
+
+when4 = 1379804850
+
+abs_ecdsa384_keys = { abs_example :
+ dns.rrset.from_text('example.', 86400, 'IN', 'DNSKEY',
+ "256 3 14 1bG8qWviKNXQX3BIuG6/T5jrP1FISiLW/8qGF6BsM9DQtWYhhZUA3Owr OAEiyHAhQwjkN2kTvWiAYoPN80Ii+5ff9/atzY4F9W50P4l75Dj9PYrL HN/hLUgWMNVc9pvA",
+ "257 3 14 mSub2n0KRt6u2FaD5XJ3oQu0R4XvB/9vUJcyW6+oo0y+KzfQeTdkf1ro ZMVKoyWXW9zUKBYGJpMUIdbAxzrYi7f5HyZ3yDpBFz1hw9+o3CX+gtgb +RyhHfJDwwFXBid9")
+ }
+
+abs_ecdsa384_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA',
+ 'ns1.example. hostmaster.example. 2 10800 3600 604800 86400')
+
+abs_other_ecdsa384_soa = dns.rrset.from_text('example.', 86400, 'IN', 'SOA',
+ 'ns1.example. hostmaster.example. 2 10800 3600 604800 86401')
+
+abs_ecdsa384_soa_rrsig = dns.rrset.from_text('example.', 86400, 'IN', 'RRSIG',
+ "SOA 14 1 86400 20130929021229 20130921230729 63571 example. CrnCu34EeeRz0fEhL9PLlwjpBKGYW8QjBjFQTwd+ViVLRAS8tNkcDwQE NhSV89NEjj7ze1a/JcCfcJ+/mZgnvH4NHLNg3Tf6KuLZsgs2I4kKQXEk 37oIHravPEOlGYNI")
+
class DNSSECValidatorTestCase(unittest.TestCase):
@unittest.skipIf(not dns.dnssec._have_pycrypto,
ds = dns.dnssec.make_ds(abs_example, example_sep_key, 'SHA256')
self.assertTrue(ds == example_ds_sha256)
+ def testAbsoluteECDSA256Good(self):
+ dns.dnssec.validate(abs_ecdsa256_soa, abs_ecdsa256_soa_rrsig,
+ abs_ecdsa256_keys, None, when3)
+
+ def testAbsoluteECDSA256Bad(self):
+ def bad():
+ dns.dnssec.validate(abs_other_ecdsa256_soa, abs_ecdsa256_soa_rrsig,
+ abs_ecdsa256_keys, None, when3)
+ self.failUnlessRaises(dns.dnssec.ValidationFailure, bad)
+
+ def testAbsoluteECDSA384Good(self):
+ dns.dnssec.validate(abs_ecdsa384_soa, abs_ecdsa384_soa_rrsig,
+ abs_ecdsa384_keys, None, when4)
+
+ def testAbsoluteECDSA384Bad(self):
+ def bad():
+ dns.dnssec.validate(abs_other_ecdsa384_soa, abs_ecdsa384_soa_rrsig,
+ abs_ecdsa384_keys, None, when4)
+ self.failUnlessRaises(dns.dnssec.ValidationFailure, bad)
+
+
if __name__ == '__main__':
import_ok = False
try: