From 7dd4fa9da313bd214cb18253fcc9f0c8a6910056 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Fri, 1 Feb 2019 18:18:34 +1100 Subject: [PATCH] enforce known SSHFP finger print lengths (cherry picked from commit 1722728c80671bb7a93944a3e8b37bc56061d5b7) --- CHANGES | 2 + lib/dns/rdata/generic/sshfp_44.c | 29 +++++++++++- lib/dns/tests/rdata_test.c | 77 ++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index f3cda8eac8..da90dc5a42 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,5 @@ +5229. [protocol] Enforce known SSHFP fingerprint lengths. [GL #852] + 5224. [bug] Only test provide-ixfr on TCP streams. [GL #991] 5223. [bug] Fixed a race in the filter-aaaa plugin accessing diff --git a/lib/dns/rdata/generic/sshfp_44.c b/lib/dns/rdata/generic/sshfp_44.c index c4209f4abc..ce60be5ae5 100644 --- a/lib/dns/rdata/generic/sshfp_44.c +++ b/lib/dns/rdata/generic/sshfp_44.c @@ -20,6 +20,7 @@ static inline isc_result_t fromtext_sshfp(ARGS_FROMTEXT) { isc_token_t token; + int len = -1; REQUIRE(type == dns_rdatatype_sshfp); @@ -47,10 +48,24 @@ fromtext_sshfp(ARGS_FROMTEXT) { RETTOK(ISC_R_RANGE); RETERR(uint8_tobuffer(token.value.as_ulong, target)); + /* + * Enforce known digest lengths. + */ + switch (token.value.as_ulong) { + case 1: + len = ISC_SHA1_DIGESTLENGTH; + break; + case 2: + len = ISC_SHA256_DIGESTLENGTH; + break; + default: + break; + } + /* * Digest. */ - return (isc_hex_tobuffer(lexer, target, -2)); + return (isc_hex_tobuffer(lexer, target, len)); } static inline isc_result_t @@ -82,6 +97,10 @@ totext_sshfp(ARGS_TOTEXT) { snprintf(buf, sizeof(buf), "%u", n); RETERR(str_totext(buf, target)); + if (sr.length == 0U) { + return (ISC_R_SUCCESS); + } + /* * Digest. */ @@ -110,8 +129,14 @@ fromwire_sshfp(ARGS_FROMWIRE) { UNUSED(options); isc_buffer_activeregion(source, &sr); - if (sr.length < 4) + if (sr.length < 2) { return (ISC_R_UNEXPECTEDEND); + } + + if ((sr.base[1] == 1 && sr.length != ISC_SHA1_DIGESTLENGTH + 2) || + (sr.base[1] == 2 && sr.length != ISC_SHA256_DIGESTLENGTH + 2)) { + return (DNS_R_FORMERR); + } isc_buffer_forward(source, sr.length); return (mem_tobuffer(target, sr.base, sr.length)); diff --git a/lib/dns/tests/rdata_test.c b/lib/dns/tests/rdata_test.c index bb2249bd1e..064f0cb614 100644 --- a/lib/dns/tests/rdata_test.c +++ b/lib/dns/tests/rdata_test.c @@ -2044,6 +2044,82 @@ rkey(void **state) { dns_rdatatype_rkey, sizeof(dns_rdata_rkey_t)); } +/* SSHFP RDATA manipulations */ +static void +sshfp(void **state) { + text_ok_t text_ok[] = { + TEXT_INVALID(""), /* too short */ + TEXT_INVALID("0"), /* reserved, too short */ + TEXT_VALID("0 0"), /* no finger print */ + TEXT_VALID("0 0 AA"), /* reserved */ + TEXT_INVALID("0 1 AA"), /* too short SHA 1 digest */ + TEXT_INVALID("0 2 AA"), /* too short SHA 256 digest */ + TEXT_VALID("0 3 AA"), /* unknown finger print type */ + /* good length SHA 1 digest */ + TEXT_VALID("1 1 00112233445566778899AABBCCDDEEFF17181920"), + /* good length SHA 256 digest */ + TEXT_VALID("4 2 A87F1B687AC0E57D2A081A2F282672334D90ED316D2B818CA9580EA3 84D92401"), + /* + * totext splits the fingerprint into chunks and + * emits uppercase hex. + */ + TEXT_VALID_CHANGED("1 2 00112233445566778899aabbccddeeff " + "00112233445566778899AABBCCDDEEFF", + "1 2 00112233445566778899AABBCCDDEEFF" + "00112233445566778899AABB CCDDEEFF"), + TEXT_SENTINEL() + }; + wire_ok_t wire_ok[] = { + WIRE_INVALID(0x00), /* reserved too short */ + WIRE_VALID(0x00, 0x00), /* reserved no finger print */ + WIRE_VALID(0x00, 0x00, 0x00), /* reserved */ + + /* too short SHA 1 digests */ + WIRE_INVALID(0x00, 0x01), + WIRE_INVALID(0x00, 0x01, 0x00), + WIRE_INVALID(0x00, 0x01, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, + 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, + 0xEE, 0xFF, 0x17, 0x18, 0x19), + /* good length SHA 1 digest */ + WIRE_VALID(0x00, 0x01, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, + 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, + 0xEE, 0xFF, 0x17, 0x18, 0x19, 0x20), + /* too long SHA 1 digest */ + WIRE_INVALID(0x00, 0x01, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, + 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, + 0xEE, 0xFF, 0x17, 0x18, 0x19, 0x20, 0x21), + /* too short SHA 256 digests */ + WIRE_INVALID(0x00, 0x02), + WIRE_INVALID(0x00, 0x02, 0x00), + WIRE_INVALID(0x00, 0x02, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, + 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, + 0xEE, 0xFF, 0x17, 0x18, 0x19, 0x20, 0x21, 0x22, + 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30, + 0x31), + /* good length SHA 256 digest */ + WIRE_VALID(0x00, 0x02, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, + 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, + 0xEE, 0xFF, 0x17, 0x18, 0x19, 0x20, 0x21, 0x22, + 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30, + 0x31, 0x32), + /* too long SHA 256 digest */ + WIRE_INVALID(0x00, 0x02, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, + 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, + 0xEE, 0xFF, 0x17, 0x18, 0x19, 0x20, 0x21, 0x22, + 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30, + 0x31, 0x32, 0x33), + /* unknown digest, * no fingerprint */ + WIRE_VALID(0x00, 0x03), + WIRE_VALID(0x00, 0x03, 0x00), /* unknown digest */ + WIRE_SENTINEL() + }; + + UNUSED(state); + + check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in, + dns_rdatatype_sshfp, sizeof(dns_rdata_sshfp_t)); +} + /* * WKS tests. * @@ -2380,6 +2456,7 @@ main(int argc, char **argv) { cmocka_unit_test_setup_teardown(nsec, _setup, _teardown), cmocka_unit_test_setup_teardown(nsec3, _setup, _teardown), cmocka_unit_test_setup_teardown(nxt, _setup, _teardown), + cmocka_unit_test_setup_teardown(sshfp, _setup, _teardown), cmocka_unit_test_setup_teardown(wks, _setup, _teardown), cmocka_unit_test_setup_teardown(rkey, _setup, _teardown), cmocka_unit_test_setup_teardown(zonemd, _setup, _teardown),