From 30e0169787ccd24f434164add18b0509d6fb1e90 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Vavru=C5=A1a?= <marek.vavrusa@nic.cz>
Date: Fri, 25 Sep 2015 13:54:30 +0200
Subject: [PATCH] lib/dnssec: accept valid and unrevoked keys (SEP not
 required), key matching

---
 lib/dnssec.c | 36 +++++++++++++++++++++++++++++++++++-
 lib/dnssec.h | 15 +++++++++++++++
 2 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/lib/dnssec.c b/lib/dnssec.c
index b3b576593..6efd0190d 100644
--- a/lib/dnssec.c
+++ b/lib/dnssec.c
@@ -249,7 +249,7 @@ int kr_dnskeys_trusted(const knot_pkt_t *pkt, knot_section_t section_id, const k
 		/* RFC4035 5.3.1, bullet 8 */ /* ZSK */
 		const knot_rdata_t *krr = knot_rdataset_at(&keys->rrs, i);
 		const uint8_t *key_data = knot_rdata_data(krr);
-		if (!kr_dnssec_key_ksk(key_data) && !kr_dnssec_key_revoked(key_data)) {
+		if (!kr_dnssec_key_zsk(key_data) || kr_dnssec_key_revoked(key_data)) {
 			continue;
 		}
 		
@@ -272,6 +272,11 @@ int kr_dnskeys_trusted(const knot_pkt_t *pkt, knot_section_t section_id, const k
 	return kr_error(ENOENT);
 }
 
+bool kr_dnssec_key_zsk(const uint8_t *dnskey_rdata)
+{
+	return wire_read_u16(dnskey_rdata) & 0x0100;
+}
+
 bool kr_dnssec_key_ksk(const uint8_t *dnskey_rdata)
 {
 	return wire_read_u16(dnskey_rdata) & 0x0001;
@@ -304,6 +309,35 @@ int kr_dnssec_key_tag(uint16_t rrtype, const uint8_t *rdata, size_t rdlen)
 	}
 }
 
+int kr_dnssec_key_match(const uint8_t *key_a_rdata, size_t key_a_rdlen,
+                        const uint8_t *key_b_rdata, size_t key_b_rdlen)
+{
+	dnssec_key_t *key_a = NULL, *key_b = NULL;
+	int ret = kr_dnssec_key_from_rdata((struct dseckey **)&key_a, NULL, key_a_rdata, key_a_rdlen);
+	if (ret != 0) {
+		return ret;
+	}
+	ret = kr_dnssec_key_from_rdata((struct dseckey **)&key_b, NULL, key_b_rdata, key_b_rdlen);
+	if (ret != 0) {
+		dnssec_key_free(key_a);
+		return ret;
+	}
+	/* If the algorithm and the public key match, we can be sure
+	 * that they are the same key. */
+	ret = kr_error(ENOENT);
+	dnssec_binary_t pk_a, pk_b;
+	if (dnssec_key_get_algorithm(key_a) == dnssec_key_get_algorithm(key_b) &&
+	    dnssec_key_get_pubkey(key_a, &pk_a) == DNSSEC_EOK &&
+	    dnssec_key_get_pubkey(key_b, &pk_b) == DNSSEC_EOK) {
+		if (pk_a.size == pk_b.size && memcmp(pk_a.data, pk_b.data, pk_a.size) == 0) {
+			ret = 0;
+		}
+	}
+	dnssec_key_free(key_a);
+	dnssec_key_free(key_b);
+	return ret;
+}
+
 int kr_dnssec_key_from_rdata(struct dseckey **key, const knot_dname_t *kown, const uint8_t *rdata, size_t rdlen)
 {
 	if (!key || !rdata || rdlen == 0) {
diff --git a/lib/dnssec.h b/lib/dnssec.h
index b7d85e214..7679f730a 100644
--- a/lib/dnssec.h
+++ b/lib/dnssec.h
@@ -88,6 +88,9 @@ int kr_dnskeys_trusted(const knot_pkt_t *pkt, knot_section_t section_id, const k
                        const knot_rrset_t *ta, const knot_dname_t *zone_name, uint32_t timestamp,
                        bool has_nsec3);
 
+/** Return true if the DNSKEY can be used as a ZSK.  */
+bool kr_dnssec_key_zsk(const uint8_t *dnskey_rdata);
+
 /** Return true if the DNSKEY indicates being KSK (=> has SEP).  */
 bool kr_dnssec_key_ksk(const uint8_t *dnskey_rdata);
 
@@ -101,6 +104,18 @@ bool kr_dnssec_key_revoked(const uint8_t *dnskey_rdata);
   * @return Key tag (positive number), or an error code
   */
 int kr_dnssec_key_tag(uint16_t rrtype, const uint8_t *rdata, size_t rdlen);
+
+/** Return 0 if the two keys are identical.
+  * @note This compares RDATA only, algorithm and public key must match.
+  * @param key_a_rdata First key RDATA
+  * @param key_a_rdlen First key RDATA length
+  * @param key_b_rdata Second key RDATA
+  * @param key_b_rdlen Second key RDATA length
+  * @return 0 if they match or an error code
+  */
+int kr_dnssec_key_match(const uint8_t *key_a_rdata, size_t key_a_rdlen,
+                        const uint8_t *key_b_rdata, size_t key_b_rdlen);
+
 /**
  * Construct a DNSSEC key.
  * @param key   Pointer to be set to newly created DNSSEC key.
-- 
GitLab