From: Kees Monshouwer Date: Tue, 10 Jan 2017 15:04:22 +0000 (+0100) Subject: update Ed25519 algorithm number and mnemonic X-Git-Tag: rec-4.0.5-rc1~1^2~11^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=abfe6717db1332c6ee215aa9fc51f411a527f682;p=thirdparty%2Fpdns.git update Ed25519 algorithm number and mnemonic http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml (cherry picked from commit 9d3727e0471f132f0294d6944349eb6afb2ba2ab) --- diff --git a/pdns/dbdnsseckeeper.cc b/pdns/dbdnsseckeeper.cc index 14e47373d4..37bd27c0d0 100644 --- a/pdns/dbdnsseckeeper.cc +++ b/pdns/dbdnsseckeeper.cc @@ -79,7 +79,7 @@ bool DNSSECKeeper::addKey(const DNSName& name, bool setSEPBit, int algorithm, in if(algorithm <= 10) throw runtime_error("Creating an algorithm " +std::to_string(algorithm)+" ("+algorithm2name(algorithm)+") key requires the size (in bits) to be passed"); else { - if(algorithm == 12 || algorithm == 13 || algorithm == 250) // GOST, ECDSAP256SHA256, ED25519SHA512 + if(algorithm == 12 || algorithm == 13 || algorithm == 15) // GOST, ECDSAP256SHA256, ED25519 bits = 256; else if(algorithm == 14) // ECDSAP384SHA384 bits = 384; diff --git a/pdns/dnssecinfra.cc b/pdns/dnssecinfra.cc index 54f6b8e79f..8a17cac035 100644 --- a/pdns/dnssecinfra.cc +++ b/pdns/dnssecinfra.cc @@ -236,7 +236,7 @@ pair DNSCryptoKeyEngine::testMakers(unsigned int alg unsigned int bits; if(algo <= 10) bits=1024; - else if(algo == 12 || algo == 13 || algo == 250) // ECC-GOST or ECDSAP256SHA256 or ED25519SHA512 + else if(algo == 12 || algo == 13 || algo == 15) // ECC-GOST or ECDSAP256SHA256 or ED25519 bits=256; else if(algo == 14) // ECDSAP384SHA384 bits = 384; diff --git a/pdns/dnsseckeeper.hh b/pdns/dnsseckeeper.hh index 38dbc56464..9c8582f3cf 100644 --- a/pdns/dnsseckeeper.hh +++ b/pdns/dnsseckeeper.hh @@ -51,7 +51,7 @@ public: ECCGOST=12, ECDSA256=13, ECDSA384=14, - EXPERIMENTALED25519=250 + ED25519=15 }; struct KeyMetaData @@ -91,7 +91,7 @@ public: if (!algorithm.compare("gost")) return ECCGOST; if (!algorithm.compare("ecdsa256")) return ECDSA256; if (!algorithm.compare("ecdsa384")) return ECDSA384; - if (!algorithm.compare("experimental-ed25519")) return EXPERIMENTALED25519; + if (!algorithm.compare("ed25519")) return ED25519; return -1; } @@ -124,8 +124,8 @@ public: return "ECDSAP256SHA256"; case ECDSA384: return "ECDSAP384SHA384"; - case EXPERIMENTALED25519: - return "ED25519SHA512"; + case ED25519: + return "ED25519"; case 252: return "INDIRECT"; case 253: diff --git a/pdns/pdnsutil.cc b/pdns/pdnsutil.cc index c2d72f86a1..5a1bd4dd81 100644 --- a/pdns/pdnsutil.cc +++ b/pdns/pdnsutil.cc @@ -1906,7 +1906,7 @@ try cout<<"add-zone-key ZONE {zsk|ksk} [BITS] [active|inactive]"<()); if(algorithm <= 10) bits = keyOrZone ? 2048 : 1024; else { - if(algorithm == 12 || algorithm == 13 || algorithm == 250) // ECDSA, GOST, ED25519 + if(algorithm == 12 || algorithm == 13 || algorithm == 15) // ECDSA, GOST, ED25519 bits = 256; else if(algorithm == 14) bits = 384; diff --git a/pdns/sodiumsigners.cc b/pdns/sodiumsigners.cc index 7c6d744dae..a937484aa4 100644 --- a/pdns/sodiumsigners.cc +++ b/pdns/sodiumsigners.cc @@ -52,12 +52,12 @@ DNSCryptoKeyEngine::storvector_t SodiumED25519DNSCryptoKeyEngine::convertToISCVe { /* Private-key-format: v1.2 - Algorithm: 250 (ED25519SHA512) + Algorithm: 15 (ED25519) PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ= */ storvector_t storvector; - string algorithm = "250 (ED25519SHA512)"; + string algorithm = "15 (ED25519)"; storvector.push_back(make_pair("Algorithm", algorithm)); @@ -70,7 +70,7 @@ void SodiumED25519DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std:: { /* Private-key-format: v1.2 - Algorithm: 250 (ED25519SHA512) + Algorithm: 15 (ED25519) PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ= */ @@ -146,7 +146,7 @@ struct LoaderSodiumStruct { LoaderSodiumStruct() { - DNSCryptoKeyEngine::report(250, &SodiumED25519DNSCryptoKeyEngine::maker); + DNSCryptoKeyEngine::report(15, &SodiumED25519DNSCryptoKeyEngine::maker); } } loadersodium; } diff --git a/regression-tests.api/test_cryptokeys.py b/regression-tests.api/test_cryptokeys.py new file mode 100644 index 0000000000..cf249beadd --- /dev/null +++ b/regression-tests.api/test_cryptokeys.py @@ -0,0 +1,267 @@ +import subprocess +import json +import unittest +import os + +from test_helper import ApiTestCase, is_auth + +@unittest.skipIf(not is_auth(), "Not applicable") +class Cryptokeys(ApiTestCase): + + def __init__(self, *args, **kwds): + super(Cryptokeys, self).__init__(*args, **kwds) + self.keyid = 0 + self.zone = "cryptokeys.org" + + def tearDown(self): + super(Cryptokeys,self).tearDown() + self.remove_zone_key(self.keyid) + + # Adding a key to self.zone using the pdnsutil command + def add_zone_key(self, status='inactive'): + try: + return subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "add-zone-key", self.zone, "ksk", status], stderr=open(os.devnull, 'wb')) + except subprocess.CalledProcessError as e: + self.fail("pdnsutil add-zone-key failed: "+e.output) + + # Removes a key from self.zone by id using the pdnsutil command + def remove_zone_key(self, key_id): + try: + subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "remove-zone-key", self.zone, str(key_id)]) + except subprocess.CalledProcessError as e: + self.fail("pdnsutil remove-zone-key failed: "+e.output) + + # This method tests the DELETE api call. + def test_delete(self): + self.keyid = self.add_zone_key() + + #checks the status code. I don't know how to test explicit that the backend fail removing a key. + r = self.session.delete(self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid)) + self.assertEquals(r.status_code, 200) + self.assertEquals(r.content, "") + + # Check that the key is actually deleted + try: + out = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "list-keys", self.zone]) + self.assertNotIn(self.zone, out) + except subprocess.CalledProcessError as e: + self.fail("pdnsutil list-keys failed: " + e.output) + + def test_delete_wrong_zone(self): + self.keyid = self.add_zone_key() + #checks for not covered zonename + r = self.session.delete(self.url("/api/v1/servers/localhost/zones/"+self.zone+"fail/cryptokeys/"+self.keyid)) + self.assertEquals(r.status_code, 400) + + def test_delete_key_is_gone(self): + self.keyid = self.add_zone_key() + self.remove_zone_key(self.keyid) + #checks for key is gone. Its ok even if no key had to be deleted. Or something went wrong with the backend. + r = self.session.delete(self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid)) + self.assertEquals(r.status_code, 200) + self.assertEquals(r.content, "") + + # Prepares the json object for Post and sends it to the server + def add_key(self, content='', type='ksk', active='true' , algo='', bits=0): + if algo == '': + payload = { + 'keytype': type, + 'active' : active + } + else: + payload = { + 'keytype': type, + 'active' : active, + 'algo' : algo + } + if bits > 0: + payload['bits'] = bits + if content != '': + payload['content'] = content + r = self.session.post( + self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys"), + data=json.dumps(payload), + headers={'content-type': 'application/json'}) + + return r + + # Test POST for a positive result and delete the added key + def post_helper(self,content='', algo='', bits=0): + r = self.add_key(content=content, algo=algo, bits=bits) + self.assert_success_json(r) + self.assertEquals(r.status_code, 201) + response = r.json() + # Only a ksk added, so expected type is csk + self.assertEquals(response['keytype'], 'csk') + self.keyid = response['id'] + # Check if the key is actually added + try: + out = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "list-keys", self.zone]) + self.assertIn(self.zone, out) + except subprocess.CalledProcessError as e: + self.fail("pdnsutil list-keys failed: " + e.output) + + # Test POST to add a key with default algorithm + def test_post(self): + self.post_helper() + + # Test POST to add a key with specific algorithm number + def test_post_specific_number(self): + self.post_helper(algo=10, bits=512) + + # Test POST to add a key with specific name and bits + def test_post_specific_name_bits(self): + self.post_helper(algo="rsasha256", bits=256) + + # Test POST to add a key with specific name + def test_post_specific_name(self): + self.post_helper(algo='ecdsa256') + + # Test POST to add a private key from external resource + def test_post_content(self): + self.post_helper(content="Private-key-format: v1.2\n"+ + "Algorithm: 8 (RSASHA256)\n"+ + "Modulus: 4GlYLGgDI7ohnP8SmEW8EBERbNRusDcg0VQda/EPVHU=\n"+ + "PublicExponent: AQAB\n"+ + "PrivateExponent: JBnuXF5zOtkjtSz3odV+Fk5UNUTTeCsiI16dkcM7TVU=\n"+ + "Prime1: /w7TM4118RoSEvP8+dgnCw==\n"+ + "Prime2: 4T2KhkYLa3w7rdK3Cb2ifw==\n"+ + "Exponent1: 3aeKj9Ct4JuhfWsgPBhGxQ==\n"+ + "Exponent2: tfh1OMPQKBdnU6iATjNR2w==\n"+ + "Coefficient: eVrHe/kauqOewSKndIImrg==)\n") + + def test_post_wrong_key_format(self): + r = self.add_key(content="trollololoooolll") + self.assert_error_json(r) + self.assertEquals(r.status_code, 422) + self.assertIn("Key could not be parsed. Make sure your key format is correct.",r.json()['error']) + + def test_post_wrong_keytype(self): + r = self.add_key(type='sdfdhhgj') + self.assert_error_json(r) + self.assertEquals(r.status_code, 422) + self.assertIn("Invalid keytype",r.json()['error']) + + def test_post_wrong_bits_format(self): + r = self.add_key(bits='sdfdhhgj') + self.assert_error_json(r) + self.assertEquals(r.status_code, 422) + self.assertIn("'bits' must be a positive integer value",r.json()['error']) + + r = self.add_key(bits='5.5') + self.assert_error_json(r) + self.assertEquals(r.status_code, 422) + self.assertIn("'bits' must be a positive integer value",r.json()['error']) + + r = self.add_key(bits='-6') + self.assert_error_json(r) + self.assertEquals(r.status_code, 422) + self.assertIn("'bits' must be a positive integer value",r.json()['error']) + + def test_post_unsupported_algorithm(self): + r = self.add_key(algo='lkjhgf') + self.assert_error_json(r) + self.assertEquals(r.status_code, 422) + self.assertIn("Unknown algorithm:",r.json()['error']) + + def test_post_forgot_bits(self): + r = self.add_key(algo="rsasha256") + self.assert_error_json(r) + self.assertEquals(r.status_code, 422) + self.assertIn("key requires the size (in bits) to be passed", r.json()['error']) + + def test_post_wrong_bit_size(self): + r = self.add_key(algo=10, bits=30) + self.assert_error_json(r) + self.assertEquals(r.status_code,422) + self.assertIn("The algorithm does not support the given bit size.", r.json()['error']) + + def test_post_can_not_guess_key_size(self): + r = self.add_key(algo=17) + self.assert_error_json(r) + self.assertEquals(r.status_code,422) + self.assertIn("Can not guess key size for algorithm", r.json()['error']) + + def test_put_activate_key(self): + self.keyid = self.add_zone_key() + + payload = { + 'active': True + } + r = self.session.put( + self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid), + data=json.dumps(payload), + headers={'content-type': 'application/json'}) + self.assertEquals(r.status_code, 204) + self.assertEquals(r.content, "") + + # check if key is activated + try: + out = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "show-zone", self.zone]) + self.assertIn("Active", out) + except subprocess.CalledProcessError as e: + self.fail("pdnsutil show-zone failed: " + e.output) + + def test_put_deactivate_key(self): + self.keyid= self.add_zone_key(status='active') + # deactivate key + payload2 = { + 'active': False + } + + r = self.session.put( + self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid), + data=json.dumps(payload2), + headers={'content-type': 'application/json'}) + self.assertEquals(r.status_code, 204) + self.assertEquals(r.content, "") + + # check if key is deactivated + try: + out = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "show-zone", self.zone]) + self.assertIn("Inactive", out) + except subprocess.CalledProcessError as e: + self.fail("pdnsutil show-zone failed: " + e.output) + + def test_put_deactivate_inactive_key(self): + self.keyid = self.add_zone_key() + + # deactivate key + payload = { + 'active': False + } + + r = self.session.put( + self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid), + data=json.dumps(payload), + headers={'content-type': 'application/json'}) + self.assertEquals(r.status_code, 204) + self.assertEquals(r.content, "") + + # check if key is still deactivated + try: + out = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "show-zone", self.zone]) + self.assertIn("Inactive", out) + except subprocess.CalledProcessError as e: + self.fail("pdnsutil show-zone failed: " + e.output) + + def test_put_activate_active_key(self): + self.keyid =self.add_zone_key(status='active') + + # activate key + payload2 = { + 'active': True + } + r = self.session.put( + self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid), + data=json.dumps(payload2), + headers={'content-type': 'application/json'}) + self.assertEquals(r.status_code, 204) + self.assertEquals(r.content, "") + + # check if key is activated + try: + out = subprocess.check_output(["../pdns/pdnsutil", "--config-dir=.", "show-zone", self.zone]) + self.assertIn("Active", out) + except subprocess.CalledProcessError as e: + self.fail("pdnsutil show-zone failed: " + e.output) \ No newline at end of file