From bfbeef3609dba1929e3df4ab980291a56387006a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Tue, 13 Mar 2018 14:06:04 +0100 Subject: [PATCH 01/10] Rework dns_test_makezone() The dns_test_makezone() helper function always assigns the created zone to some view, which is not always necessary and complicates cleanup of non-managed zones as they are required not to be assigned to any view. Rework dns_test_makezone() in order to make it easier to use in unit tests operating on non-managed zones. Use dns_name_fromstring() instead of dns_name_fromtext() to simplify code. Do not use the CHECK() macro and add comments to make code flow simpler to follow. Use dns_test_makeview() instead of dns_view_create(). Adjust existing unit tests using this function so that they still pass. --- lib/dns/tests/dnstest.c | 83 +++++++++++++++++++++++------------------ lib/dns/tests/dnstest.h | 18 ++++++++- lib/dns/tests/zt_test.c | 6 +-- 3 files changed, 66 insertions(+), 41 deletions(-) diff --git a/lib/dns/tests/dnstest.c b/lib/dns/tests/dnstest.c index 4fe5647aef..8c8e5bfec9 100644 --- a/lib/dns/tests/dnstest.c +++ b/lib/dns/tests/dnstest.c @@ -201,57 +201,68 @@ dns_test_makeview(const char *name, dns_view_t **viewp) { return (result); } -/* - * Create a zone with origin 'name', return a pointer to the zone object in - * 'zonep'. If 'view' is set, add the zone to that view; otherwise, create - * a new view for the purpose. - * - * If the created view is going to be needed by the caller subsequently, - * then 'keepview' should be set to true; this will prevent the view - * from being detached. In this case, the caller is responsible for - * detaching the view. - */ isc_result_t dns_test_makezone(const char *name, dns_zone_t **zonep, dns_view_t *view, - isc_boolean_t keepview) + isc_boolean_t createview) { - isc_result_t result; + dns_fixedname_t fixed_origin; dns_zone_t *zone = NULL; - isc_buffer_t buffer; - dns_fixedname_t fixorigin; + isc_result_t result; dns_name_t *origin; - if (view == NULL) - CHECK(dns_view_create(mctx, dns_rdataclass_in, "view", &view)); - else if (!keepview) - keepview = ISC_TRUE; + REQUIRE(view == NULL || !createview); - zone = *zonep; - if (zone == NULL) - CHECK(dns_zone_create(&zone, mctx)); + /* + * Create the zone structure. + */ + result = dns_zone_create(&zone, mctx); + if (result != ISC_R_SUCCESS) { + return (result); + } - isc_buffer_constinit(&buffer, name, strlen(name)); - isc_buffer_add(&buffer, strlen(name)); - origin = dns_fixedname_initname(&fixorigin); - CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL)); - CHECK(dns_zone_setorigin(zone, origin)); - dns_zone_setview(zone, view); + /* + * Set zone type and origin. + */ dns_zone_settype(zone, dns_zone_master); - dns_zone_setclass(zone, view->rdclass); - dns_view_addzone(view, zone); + origin = dns_fixedname_initname(&fixed_origin); + result = dns_name_fromstring(origin, name, 0, NULL); + if (result != ISC_R_SUCCESS) { + goto detach_zone; + } + result = dns_zone_setorigin(zone, origin); + if (result != ISC_R_SUCCESS) { + goto detach_zone; + } - if (!keepview) - dns_view_detach(&view); + /* + * If requested, create a view. + */ + if (createview) { + result = dns_test_makeview("view", &view); + if (result != ISC_R_SUCCESS) { + goto detach_zone; + } + } + + /* + * If a view was passed as an argument or created above, attach the + * created zone to it. Otherwise, set the zone's class to IN. + */ + if (view != NULL) { + dns_zone_setview(zone, view); + dns_zone_setclass(zone, view->rdclass); + dns_view_addzone(view, zone); + } else { + dns_zone_setclass(zone, dns_rdataclass_in); + } *zonep = zone; return (ISC_R_SUCCESS); - cleanup: - if (zone != NULL) - dns_zone_detach(&zone); - if (view != NULL) - dns_view_detach(&view); + detach_zone: + dns_zone_detach(&zone); + return (result); } diff --git a/lib/dns/tests/dnstest.h b/lib/dns/tests/dnstest.h index e9f48097b8..f255493a70 100644 --- a/lib/dns/tests/dnstest.h +++ b/lib/dns/tests/dnstest.h @@ -54,9 +54,25 @@ dns_test_end(void); isc_result_t dns_test_makeview(const char *name, dns_view_t **viewp); +/*% + * Create a zone with origin 'name', return a pointer to the zone object in + * 'zonep'. + * + * If 'view' is set, the returned zone will be assigned to the passed view. + * 'createview' must be set to false when 'view' is non-NULL. + * + * If 'view' is not set and 'createview' is true, a new view is also created + * and the returned zone is assigned to it. This imposes two requirements on + * the caller: 1) the returned zone has to be subsequently assigned to a zone + * manager, otherwise its cleanup will fail, 2) the created view has to be + * cleaned up by the caller. + * + * If 'view' is not set and 'createview' is false, the returned zone will not + * be assigned to any view. + */ isc_result_t dns_test_makezone(const char *name, dns_zone_t **zonep, dns_view_t *view, - isc_boolean_t keepview); + isc_boolean_t createview); isc_result_t dns_test_setupzonemgr(void); diff --git a/lib/dns/tests/zt_test.c b/lib/dns/tests/zt_test.c index 6fed4a4769..699569716f 100644 --- a/lib/dns/tests/zt_test.c +++ b/lib/dns/tests/zt_test.c @@ -9,8 +9,6 @@ * information regarding copyright ownership. */ -/* $Id$ */ - /*! \file */ #include @@ -222,13 +220,13 @@ ATF_TC_BODY(asyncload_zt, tc) { dns_masterformat_text, &dns_master_style_default); view = dns_zone_getview(zone1); - result = dns_test_makezone("bar", &zone2, view, ISC_TRUE); + result = dns_test_makezone("bar", &zone2, view, ISC_FALSE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); dns_zone_setfile(zone2, "testdata/zt/zone1.db", dns_masterformat_text, &dns_master_style_default); /* This one will fail to load */ - result = dns_test_makezone("fake", &zone3, view, ISC_TRUE); + result = dns_test_makezone("fake", &zone3, view, ISC_FALSE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); dns_zone_setfile(zone3, "testdata/zt/nonexistent.db", dns_masterformat_text, &dns_master_style_default); From 2980cbd55f4fc56b5a4115ccd2e6d46ada6dcdf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Wed, 9 May 2018 13:12:08 +0200 Subject: [PATCH 02/10] Rename dns_test_rdata_fromstring() to dns_test_rdatafromstring() Remove the underscore from "rdata_fromstring" so that all helper functions for libdns tests use a common naming covention. --- lib/dns/tests/dnstest.c | 6 +++--- lib/dns/tests/dnstest.h | 6 +++--- lib/dns/tests/nsec3_test.c | 8 ++++---- lib/dns/tests/rdata_test.c | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/dns/tests/dnstest.c b/lib/dns/tests/dnstest.c index 8c8e5bfec9..83e40256d4 100644 --- a/lib/dns/tests/dnstest.c +++ b/lib/dns/tests/dnstest.c @@ -442,9 +442,9 @@ dns_test_getdata(const char *file, unsigned char *buf, } isc_result_t -dns_test_rdata_fromstring(dns_rdata_t *rdata, dns_rdataclass_t rdclass, - dns_rdatatype_t rdtype, unsigned char *dst, - size_t dstlen, const char *src) +dns_test_rdatafromstring(dns_rdata_t *rdata, dns_rdataclass_t rdclass, + dns_rdatatype_t rdtype, unsigned char *dst, + size_t dstlen, const char *src) { isc_buffer_t source, target; isc_lex_t *lex = NULL; diff --git a/lib/dns/tests/dnstest.h b/lib/dns/tests/dnstest.h index f255493a70..492bc42a38 100644 --- a/lib/dns/tests/dnstest.h +++ b/lib/dns/tests/dnstest.h @@ -106,9 +106,9 @@ dns_test_tohex(const unsigned char *data, size_t len, char *buf, size_t buflen); * uncompressed wire form of that RDATA at "dst", which is "dstlen" bytes long. */ isc_result_t -dns_test_rdata_fromstring(dns_rdata_t *rdata, dns_rdataclass_t rdclass, - dns_rdatatype_t rdtype, unsigned char *dst, - size_t dstlen, const char *src); +dns_test_rdatafromstring(dns_rdata_t *rdata, dns_rdataclass_t rdclass, + dns_rdatatype_t rdtype, unsigned char *dst, + size_t dstlen, const char *src); void dns_test_namefromstring(const char *namestr, dns_fixedname_t *fname); diff --git a/lib/dns/tests/nsec3_test.c b/lib/dns/tests/nsec3_test.c index e0d802c3f2..51f57fdd59 100644 --- a/lib/dns/tests/nsec3_test.c +++ b/lib/dns/tests/nsec3_test.c @@ -74,10 +74,10 @@ nsec3param_salttotext_test(const nsec3param_salttotext_test_params_t *params) { /* * Prepare a dns_rdata_nsec3param_t structure for testing. */ - result = dns_test_rdata_fromstring(&rdata, dns_rdataclass_in, - dns_rdatatype_nsec3param, buf, - sizeof(buf), - params->nsec3param_text); + result = dns_test_rdatafromstring(&rdata, dns_rdataclass_in, + dns_rdatatype_nsec3param, buf, + sizeof(buf), + params->nsec3param_text); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); diff --git a/lib/dns/tests/rdata_test.c b/lib/dns/tests/rdata_test.c index 0a9b94b2d6..d145bd5cd8 100644 --- a/lib/dns/tests/rdata_test.c +++ b/lib/dns/tests/rdata_test.c @@ -153,9 +153,9 @@ check_text_ok_single(const text_ok_t *text_ok, dns_rdataclass_t rdclass, /* * Try converting text form RDATA into uncompressed wire form. */ - result = dns_test_rdata_fromstring(&rdata, rdclass, type, buf_fromtext, - sizeof(buf_fromtext), - text_ok->text_in); + result = dns_test_rdatafromstring(&rdata, rdclass, type, buf_fromtext, + sizeof(buf_fromtext), + text_ok->text_in); /* * Check whether result is as expected. */ From 3c22af0d35ada9f83557845d481ef1c9257ae383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Tue, 13 Mar 2018 14:06:06 +0100 Subject: [PATCH 03/10] Add a helper function to facilitate preparing dns_diff_t structures Implement dns_test_difffromchanges(), a function which enables preparing a dns_diff_t structure from a mostly-textual representation of zone database changes to be applied. This will improve readability of test case definitions by allowing contents of a dns_diff_t structure, passed e.g. to update_sigs(), to be represented in a human-friendly manner. --- lib/dns/tests/dnstest.c | 69 +++++++++++++++++++++++++++++++++++++++++ lib/dns/tests/dnstest.h | 18 +++++++++++ 2 files changed, 87 insertions(+) diff --git a/lib/dns/tests/dnstest.c b/lib/dns/tests/dnstest.c index 83e40256d4..acec5ec753 100644 --- a/lib/dns/tests/dnstest.c +++ b/lib/dns/tests/dnstest.c @@ -516,3 +516,72 @@ dns_test_namefromstring(const char *namestr, dns_fixedname_t *fname) { isc_buffer_free(&b); } + +isc_result_t +dns_test_difffromchanges(dns_diff_t *diff, const zonechange_t *changes) { + isc_result_t result = ISC_R_SUCCESS; + unsigned char rdata_buf[1024]; + dns_difftuple_t *tuple = NULL; + isc_consttextregion_t region; + dns_rdatatype_t rdatatype; + dns_fixedname_t fixedname; + dns_rdata_t rdata; + dns_name_t *name; + size_t i; + + REQUIRE(diff != NULL); + REQUIRE(changes != NULL); + + dns_diff_init(mctx, diff); + + for (i = 0; changes[i].owner != NULL; i++) { + /* + * Parse owner name. + */ + name = dns_fixedname_initname(&fixedname); + result = dns_name_fromstring(name, changes[i].owner, 0, mctx); + if (result != ISC_R_SUCCESS) { + break; + } + + /* + * Parse RDATA type. + */ + region.base = changes[i].type; + region.length = strlen(changes[i].type); + result = dns_rdatatype_fromtext(&rdatatype, + (isc_textregion_t *)®ion); + if (result != ISC_R_SUCCESS) { + break; + } + + /* + * Parse RDATA. + */ + dns_rdata_init(&rdata); + result = dns_test_rdatafromstring(&rdata, dns_rdataclass_in, + rdatatype, rdata_buf, + sizeof(rdata_buf), + changes[i].rdata); + if (result != ISC_R_SUCCESS) { + break; + } + + /* + * Create a diff tuple for the parsed change and append it to + * the diff. + */ + result = dns_difftuple_create(mctx, changes[i].op, name, + changes[i].ttl, &rdata, &tuple); + if (result != ISC_R_SUCCESS) { + break; + } + dns_diff_append(diff, &tuple); + } + + if (result != ISC_R_SUCCESS) { + dns_diff_clear(diff); + } + + return (result); +} diff --git a/lib/dns/tests/dnstest.h b/lib/dns/tests/dnstest.h index 492bc42a38..8487c4f0d4 100644 --- a/lib/dns/tests/dnstest.h +++ b/lib/dns/tests/dnstest.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -33,6 +34,16 @@ goto cleanup; \ } while (0) +typedef struct { + dns_diffop_t op; + const char *owner; + dns_ttl_t ttl; + const char *type; + const char *rdata; +} zonechange_t; + +#define ZONECHANGE_SENTINEL { 0, NULL, 0, NULL, NULL } + extern isc_mem_t *mctx; extern isc_entropy_t *ectx; extern isc_log_t *lctx; @@ -112,3 +123,10 @@ dns_test_rdatafromstring(dns_rdata_t *rdata, dns_rdataclass_t rdclass, void dns_test_namefromstring(const char *namestr, dns_fixedname_t *fname); + +/*% + * Given a pointer to an uninitialized dns_diff_t structure in 'diff', make it + * contain diff tuples representing zone database changes listed in 'changes'. + */ +isc_result_t +dns_test_difffromchanges(dns_diff_t *diff, const zonechange_t *changes); From c1bc3be80692606c13b4549d3718ad2116718d6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Tue, 13 Mar 2018 14:06:07 +0100 Subject: [PATCH 04/10] Add lib/dns/zone_p.h Add a new private header file, lib/dns/zone_p.h, which will hold type definitions and function prototypes not meant to be exported by libdns, but required by zone-related unit tests. --- lib/dns/zone.c | 2 ++ lib/dns/zone_p.h | 26 ++++++++++++++++++++++++++ util/copyrights | 1 + 3 files changed, 29 insertions(+) create mode 100644 lib/dns/zone_p.h diff --git a/lib/dns/zone.c b/lib/dns/zone.c index ddee2f2dfa..e6f48864e8 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -79,6 +79,8 @@ #include +#include "zone_p.h" + #define ZONE_MAGIC ISC_MAGIC('Z', 'O', 'N', 'E') #define DNS_ZONE_VALID(zone) ISC_MAGIC_VALID(zone, ZONE_MAGIC) diff --git a/lib/dns/zone_p.h b/lib/dns/zone_p.h new file mode 100644 index 0000000000..24329b0e49 --- /dev/null +++ b/lib/dns/zone_p.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef DNS_ZONE_P_H +#define DNS_ZONE_P_H + +/*! \file */ + +/*% + * Types and functions below not be used outside this module and its + * associated unit tests. + */ + +ISC_LANG_BEGINDECLS + +ISC_LANG_ENDDECLS + +#endif /* DNS_ZONE_P_H */ diff --git a/util/copyrights b/util/copyrights index 938733a058..2779a8070a 100644 --- a/util/copyrights +++ b/util/copyrights @@ -3410,6 +3410,7 @@ ./lib/dns/win32/version.c C 1998,1999,2000,2001,2004,2007,2013,2016,2018 ./lib/dns/xfrin.c C 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2011,2012,2013,2014,2015,2016,2017,2018 ./lib/dns/zone.c C 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018 +./lib/dns/zone_p.h C 2018 ./lib/dns/zonekey.c C 2001,2003,2004,2005,2007,2016,2018 ./lib/dns/zt.c C 1999,2000,2001,2002,2004,2005,2006,2007,2011,2012,2013,2014,2015,2016,2017,2018 ./lib/irs/Atffile X 2016,2018 From ace465a9f924ca445eb31c925abde864a4f2adea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Tue, 13 Mar 2018 14:06:08 +0100 Subject: [PATCH 05/10] Move zonediff_t to lib/dns/zone_p.h Rename zonediff_t to dns__zonediff_t and move it to lib/dns/zone_p.h, so that unit tests can be written for functions taking pointers to structures of this type as arguments. --- lib/dns/zone.c | 23 +++++++++-------------- lib/dns/zone_p.h | 5 +++++ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/dns/zone.c b/lib/dns/zone.c index e6f48864e8..fd716e12f8 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -433,14 +433,9 @@ struct dns_zone { isc_stats_t *gluecachestats; }; -typedef struct { - dns_diff_t *diff; - isc_boolean_t offline; -} zonediff_t; - #define zonediff_init(z, d) \ do { \ - zonediff_t *_z = (z); \ + dns__zonediff_t *_z = (z); \ (_z)->diff = (d); \ (_z)->offline = ISC_FALSE; \ } while (0) @@ -6001,7 +5996,7 @@ find_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, } static isc_result_t -offline(dns_db_t *db, dns_dbversion_t *ver, zonediff_t *zonediff, +offline(dns_db_t *db, dns_dbversion_t *ver, dns__zonediff_t *zonediff, dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata) { isc_result_t result; @@ -6110,7 +6105,7 @@ delsig_ok(dns_rdata_rrsig_t *rrsig_ptr, dst_key_t **keys, unsigned int nkeys, */ static isc_result_t del_sigs(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, - dns_rdatatype_t type, zonediff_t *zonediff, dst_key_t **keys, + dns_rdatatype_t type, dns__zonediff_t *zonediff, dst_key_t **keys, unsigned int nkeys, isc_stdtime_t now, isc_boolean_t incremental) { isc_result_t result; @@ -6403,7 +6398,7 @@ zone_resigninc(dns_zone_t *zone) { dns_db_t *db = NULL; dns_dbversion_t *version = NULL; dns_diff_t _sig_diff; - zonediff_t zonediff; + dns__zonediff_t zonediff; dns_fixedname_t fixed; dns_name_t *name; dns_rdataset_t rdataset; @@ -7293,7 +7288,7 @@ update_sigs(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *version, isc_stdtime_t inception, isc_stdtime_t expire, isc_stdtime_t keyexpire, isc_stdtime_t now, isc_boolean_t check_ksk, isc_boolean_t keyset_kskonly, - zonediff_t *zonediff) + dns__zonediff_t *zonediff) { dns_difftuple_t *tuple; isc_result_t result; @@ -7360,7 +7355,7 @@ zone_nsec3chain(dns_zone_t *zone) { dns_diff_t nsec_diff; dns_diff_t nsec3_diff; dns_diff_t param_diff; - zonediff_t zonediff; + dns__zonediff_t zonediff; dns_fixedname_t fixed; dns_fixedname_t nextfixed; dns_name_t *name, *nextname; @@ -8256,7 +8251,7 @@ zone_sign(dns_zone_t *zone) { dns_dbversion_t *version = NULL; dns_diff_t _sig_diff; dns_diff_t post_diff; - zonediff_t zonediff; + dns__zonediff_t zonediff; dns_fixedname_t fixed; dns_fixedname_t nextfixed; dns_name_t *name, *nextname; @@ -17515,7 +17510,7 @@ add_signing_records(dns_db_t *db, dns_rdatatype_t privatetype, static isc_result_t sign_apex(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, - isc_stdtime_t now, dns_diff_t *diff, zonediff_t *zonediff) + isc_stdtime_t now, dns_diff_t *diff, dns__zonediff_t *zonediff) { isc_result_t result; isc_stdtime_t inception, soaexpire, keyexpire; @@ -17741,7 +17736,7 @@ zone_rekey(dns_zone_t *zone) { dns_dnsseckeylist_t dnskeys, keys, rmkeys; dns_dnsseckey_t *key; dns_diff_t diff, _sig_diff; - zonediff_t zonediff; + dns__zonediff_t zonediff; isc_boolean_t commit = ISC_FALSE, newactive = ISC_FALSE; isc_boolean_t newalg = ISC_FALSE; isc_boolean_t fullsign; diff --git a/lib/dns/zone_p.h b/lib/dns/zone_p.h index 24329b0e49..3ef05e023c 100644 --- a/lib/dns/zone_p.h +++ b/lib/dns/zone_p.h @@ -21,6 +21,11 @@ ISC_LANG_BEGINDECLS +typedef struct { + dns_diff_t *diff; + isc_boolean_t offline; +} dns__zonediff_t; + ISC_LANG_ENDDECLS #endif /* DNS_ZONE_P_H */ From b1947cee8210844b917320453cb308fbe168d320 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Tue, 13 Mar 2018 14:06:09 +0100 Subject: [PATCH 06/10] Move update_sigs() to lib/dns/zone_p.h Rename update_sigs() to dns__zone_updatesigs() and move it to lib/dns/zone_p.h, so that it can be unit tested. Add a comment describing the purpose of this function. --- lib/dns/win32/libdns.def.in | 1 + lib/dns/zone.c | 75 +++++++++++++++++++++---------------- lib/dns/zone_p.h | 8 ++++ 3 files changed, 51 insertions(+), 33 deletions(-) diff --git a/lib/dns/win32/libdns.def.in b/lib/dns/win32/libdns.def.in index ebebd170cd..6e6086ba6b 100644 --- a/lib/dns/win32/libdns.def.in +++ b/lib/dns/win32/libdns.def.in @@ -8,6 +8,7 @@ dns__rbt_checkproperties dns__rbt_getheight dns__rbtnode_getdistance dns__zone_loadpending +dns__zone_updatesigs dns_acl_allowed dns_acl_any diff --git a/lib/dns/zone.c b/lib/dns/zone.c index fd716e12f8..9c9fc5bef8 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -7282,13 +7282,18 @@ need_nsec_chain(dns_db_t *db, dns_dbversion_t *ver, return (result); } -static isc_result_t -update_sigs(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *version, - dst_key_t *zone_keys[], unsigned int nkeys, dns_zone_t *zone, - isc_stdtime_t inception, isc_stdtime_t expire, - isc_stdtime_t keyexpire, isc_stdtime_t now, - isc_boolean_t check_ksk, isc_boolean_t keyset_kskonly, - dns__zonediff_t *zonediff) +/*% + * Add/remove DNSSEC signatures for the list of "raw" zone changes supplied in + * 'diff'. Gradually remove tuples from 'diff' and append them to 'zonediff' + * along with tuples representing relevant signature changes. + */ +isc_result_t +dns__zone_updatesigs(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *version, + dst_key_t *zone_keys[], unsigned int nkeys, + dns_zone_t *zone, isc_stdtime_t inception, + isc_stdtime_t expire, isc_stdtime_t keyexpire, + isc_stdtime_t now, isc_boolean_t check_ksk, + isc_boolean_t keyset_kskonly, dns__zonediff_t *zonediff) { dns_difftuple_t *tuple; isc_result_t result; @@ -7311,7 +7316,7 @@ update_sigs(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *version, zone_keys, nkeys, now, ISC_FALSE); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, - "update_sigs:del_sigs -> %s", + "dns__zone_updatesigs:del_sigs -> %s", dns_result_totext(result)); return (result); } @@ -7321,7 +7326,7 @@ update_sigs(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *version, exp, check_ksk, keyset_kskonly); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, - "update_sigs:add_sigs -> %s", + "dns__zone_updatesigs:add_sigs -> %s", dns_result_totext(result)); return (result); } @@ -7486,7 +7491,7 @@ zone_nsec3chain(dns_zone_t *zone) { * * Note that the "signatures" variable is only used here to limit the * amount of work performed. Actual DNSSEC signatures are only - * generated by update_sigs() calls later in this function. + * generated by dns__zone_updatesigs() calls later in this function. */ while (nsec3chain != NULL && nodes-- > 0 && signatures > 0) { LOCK_ZONE(zone); @@ -7970,12 +7975,13 @@ zone_nsec3chain(dns_zone_t *zone) { */ if (nsec3chain != NULL) dns_dbiterator_pause(nsec3chain->dbiterator); - result = update_sigs(&nsec3_diff, db, version, zone_keys, - nkeys, zone, inception, expire, 0, now, - check_ksk, keyset_kskonly, &zonediff); + result = dns__zone_updatesigs(&nsec3_diff, db, version, zone_keys, + nkeys, zone, inception, expire, 0, now, + check_ksk, keyset_kskonly, &zonediff); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" - "update_sigs -> %s", dns_result_totext(result)); + "dns__zone_updatesigs -> %s", + dns_result_totext(result)); goto failure; } @@ -7983,12 +7989,13 @@ zone_nsec3chain(dns_zone_t *zone) { * We have changed the NSEC3PARAM or private RRsets * above so we need to update the signatures. */ - result = update_sigs(¶m_diff, db, version, zone_keys, - nkeys, zone, inception, expire, 0, now, - check_ksk, keyset_kskonly, &zonediff); + result = dns__zone_updatesigs(¶m_diff, db, version, zone_keys, + nkeys, zone, inception, expire, 0, now, + check_ksk, keyset_kskonly, &zonediff); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" - "update_sigs -> %s", dns_result_totext(result)); + "dns__zone_updatesigs -> %s", + dns_result_totext(result)); goto failure; } @@ -8003,12 +8010,13 @@ zone_nsec3chain(dns_zone_t *zone) { } } - result = update_sigs(&nsec_diff, db, version, zone_keys, - nkeys, zone, inception, expire, 0, now, - check_ksk, keyset_kskonly, &zonediff); + result = dns__zone_updatesigs(&nsec_diff, db, version, zone_keys, + nkeys, zone, inception, expire, 0, now, + check_ksk, keyset_kskonly, &zonediff); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" - "update_sigs -> %s", dns_result_totext(result)); + "dns__zone_updatesigs -> %s", + dns_result_totext(result)); goto failure; } @@ -8586,12 +8594,14 @@ zone_sign(dns_zone_t *zone) { } if (ISC_LIST_HEAD(post_diff.tuples) != NULL) { - result = update_sigs(&post_diff, db, version, zone_keys, - nkeys, zone, inception, expire, 0, now, - check_ksk, keyset_kskonly, &zonediff); + result = dns__zone_updatesigs(&post_diff, db, version, + zone_keys, nkeys, zone, + inception, expire, 0, now, + check_ksk, keyset_kskonly, + &zonediff); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, "zone_sign:" - "update_sigs -> %s", + "dns__zone_updatesigs -> %s", dns_result_totext(result)); goto failure; } @@ -17542,9 +17552,8 @@ sign_apex(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, keyset_kskonly = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_DNSKEYKSKONLY); /* - * See if update_sigs will update DNSKEY signature and if not - * cause them to sign so that so that newly activated keys - * are used. + * See if dns__zone_updatesigs() will update DNSKEY signature and if + * not cause them to sign so that newly activated keys are used. */ for (tuple = ISC_LIST_HEAD(diff->tuples); tuple != NULL; @@ -17576,13 +17585,13 @@ sign_apex(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, } } - result = update_sigs(diff, db, ver, zone_keys, nkeys, zone, - inception, soaexpire, keyexpire, now, - check_ksk, keyset_kskonly, zonediff); + result = dns__zone_updatesigs(diff, db, ver, zone_keys, nkeys, zone, + inception, soaexpire, keyexpire, now, + check_ksk, keyset_kskonly, zonediff); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, - "sign_apex:update_sigs -> %s", + "sign_apex:dns__zone_updatesigs -> %s", dns_result_totext(result)); goto failure; } diff --git a/lib/dns/zone_p.h b/lib/dns/zone_p.h index 3ef05e023c..bcb6e7edc6 100644 --- a/lib/dns/zone_p.h +++ b/lib/dns/zone_p.h @@ -26,6 +26,14 @@ typedef struct { isc_boolean_t offline; } dns__zonediff_t; +isc_result_t +dns__zone_updatesigs(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *version, + dst_key_t *zone_keys[], unsigned int nkeys, + dns_zone_t *zone, isc_stdtime_t inception, + isc_stdtime_t expire, isc_stdtime_t keyxpire, + isc_stdtime_t now, isc_boolean_t check_ksk, + isc_boolean_t keyset_kskonly, dns__zonediff_t *zonediff); + ISC_LANG_ENDDECLS #endif /* DNS_ZONE_P_H */ From d7143986b1c43884d89383ef7a2e1127e8324d33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Tue, 13 Mar 2018 14:06:10 +0100 Subject: [PATCH 07/10] Move find_zone_keys() to lib/dns/zone_p.h Rename find_zone_keys() to dns__zone_findkeys() and move it to lib/dns/zone_p.h, so that it can be used in unit tests. Add a comment describing the purpose of this function. --- lib/dns/win32/libdns.def.in | 1 + lib/dns/zone.c | 38 +++++++++++++++++++++---------------- lib/dns/zone_p.h | 5 +++++ 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/lib/dns/win32/libdns.def.in b/lib/dns/win32/libdns.def.in index 6e6086ba6b..6c7fa84146 100644 --- a/lib/dns/win32/libdns.def.in +++ b/lib/dns/win32/libdns.def.in @@ -7,6 +7,7 @@ EXPORTS dns__rbt_checkproperties dns__rbt_getheight dns__rbtnode_getdistance +dns__zone_findkeys dns__zone_loadpending dns__zone_updatesigs diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 9c9fc5bef8..568e4727f7 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -5973,10 +5973,16 @@ was_dumping(dns_zone_t *zone) { return (dumping); } -static isc_result_t -find_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, - isc_stdtime_t now, isc_mem_t *mctx, unsigned int maxkeys, - dst_key_t **keys, unsigned int *nkeys) +/*% + * Find up to 'maxkeys' DNSSEC keys used for signing version 'ver' of database + * 'db' for zone 'zone' in its key directory, then load these keys into 'keys'. + * Only load the public part of a given key if it is not active at timestamp + * 'now'. Store the number of keys found in 'nkeys'. + */ +isc_result_t +dns__zone_findkeys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, + isc_stdtime_t now, isc_mem_t *mctx, unsigned int maxkeys, + dst_key_t **keys, unsigned int *nkeys) { isc_result_t result; dns_dbnode_t *node = NULL; @@ -6443,11 +6449,11 @@ zone_resigninc(dns_zone_t *zone) { isc_stdtime_get(&now); - result = find_zone_keys(zone, db, version, now, zone->mctx, - DNS_MAXZONEKEYS, zone_keys, &nkeys); + result = dns__zone_findkeys(zone, db, version, now, zone->mctx, + DNS_MAXZONEKEYS, zone_keys, &nkeys); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, - "zone_resigninc:find_zone_keys -> %s", + "zone_resigninc:dns__zone_findkeys -> %s", dns_result_totext(result)); goto failure; } @@ -7434,11 +7440,11 @@ zone_nsec3chain(dns_zone_t *zone) { isc_stdtime_get(&now); - result = find_zone_keys(zone, db, version, now, zone->mctx, - DNS_MAXZONEKEYS, zone_keys, &nkeys); + result = dns__zone_findkeys(zone, db, version, now, zone->mctx, + DNS_MAXZONEKEYS, zone_keys, &nkeys); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, - "zone_nsec3chain:find_zone_keys -> %s", + "zone_nsec3chain:dns__zone_findkeys -> %s", dns_result_totext(result)); goto failure; } @@ -8318,11 +8324,11 @@ zone_sign(dns_zone_t *zone) { isc_stdtime_get(&now); - result = find_zone_keys(zone, db, version, now, zone->mctx, - DNS_MAXZONEKEYS, zone_keys, &nkeys); + result = dns__zone_findkeys(zone, db, version, now, zone->mctx, + DNS_MAXZONEKEYS, zone_keys, &nkeys); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, - "zone_sign:find_zone_keys -> %s", + "zone_sign:dns__zone_findkeys -> %s", dns_result_totext(result)); goto failure; } @@ -17529,11 +17535,11 @@ sign_apex(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, unsigned int nkeys = 0, i; dns_difftuple_t *tuple; - result = find_zone_keys(zone, db, ver, now, zone->mctx, - DNS_MAXZONEKEYS, zone_keys, &nkeys); + result = dns__zone_findkeys(zone, db, ver, now, zone->mctx, + DNS_MAXZONEKEYS, zone_keys, &nkeys); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, - "sign_apex:find_zone_keys -> %s", + "sign_apex:dns__zone_findkeys -> %s", dns_result_totext(result)); return (result); } diff --git a/lib/dns/zone_p.h b/lib/dns/zone_p.h index bcb6e7edc6..d652e5ab9f 100644 --- a/lib/dns/zone_p.h +++ b/lib/dns/zone_p.h @@ -26,6 +26,11 @@ typedef struct { isc_boolean_t offline; } dns__zonediff_t; +isc_result_t +dns__zone_findkeys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, + isc_stdtime_t now, isc_mem_t *mctx, unsigned int maxkeys, + dst_key_t **keys, unsigned int *nkeys); + isc_result_t dns__zone_updatesigs(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *version, dst_key_t *zone_keys[], unsigned int nkeys, From 1f10186476042562f2858e14331b5e76b2e54b83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Tue, 13 Mar 2018 14:06:11 +0100 Subject: [PATCH 08/10] Add a framework for dns__zone_updatesigs() unit tests Add a new ATF test, sigs_test, containing everything required to start defining test cases for dns__zone_updatesigs(). The framework is written in a way which ensures that changes to zone database applied by any dns__zone_updatesigs() invocation are preserved between subsequent checks. --- lib/dns/tests/Atffile | 1 + lib/dns/tests/Kyuafile | 1 + lib/dns/tests/Makefile.in | 7 + lib/dns/tests/sigs_test.c | 347 ++++++++++++++++++ lib/dns/tests/testdata/master/master18.data | 10 + .../tests/testkeys/Kexample.+008+20386.key | 5 + .../testkeys/Kexample.+008+20386.private | 13 + .../tests/testkeys/Kexample.+008+37464.key | 5 + .../testkeys/Kexample.+008+37464.private | 13 + util/copyrights | 6 + 10 files changed, 408 insertions(+) create mode 100644 lib/dns/tests/sigs_test.c create mode 100644 lib/dns/tests/testdata/master/master18.data create mode 100644 lib/dns/tests/testkeys/Kexample.+008+20386.key create mode 100644 lib/dns/tests/testkeys/Kexample.+008+20386.private create mode 100644 lib/dns/tests/testkeys/Kexample.+008+37464.key create mode 100644 lib/dns/tests/testkeys/Kexample.+008+37464.private diff --git a/lib/dns/tests/Atffile b/lib/dns/tests/Atffile index e13b2dc396..f27777eb46 100644 --- a/lib/dns/tests/Atffile +++ b/lib/dns/tests/Atffile @@ -27,6 +27,7 @@ tp: rdataset_test tp: rdatasetstats_test tp: resolver_test tp: rsa_test +tp: sigs_test tp: time_test tp: tsig_test tp: update_test diff --git a/lib/dns/tests/Kyuafile b/lib/dns/tests/Kyuafile index 52bd99a4c1..cb2324d5ce 100644 --- a/lib/dns/tests/Kyuafile +++ b/lib/dns/tests/Kyuafile @@ -26,6 +26,7 @@ atf_test_program{name='rdataset_test'} atf_test_program{name='rdatasetstats_test'} atf_test_program{name='resolver_test'} atf_test_program{name='rsa_test'} +atf_test_program{name='sigs_test'} atf_test_program{name='time_test'} atf_test_program{name='tsig_test'} atf_test_program{name='update_test'} diff --git a/lib/dns/tests/Makefile.in b/lib/dns/tests/Makefile.in index cfc33a0766..75a8c3f8b6 100644 --- a/lib/dns/tests/Makefile.in +++ b/lib/dns/tests/Makefile.in @@ -56,6 +56,7 @@ SRCS = acl_test.c \ rdatasetstats_test.c \ resolver_test.c \ rsa_test.c \ + sigs_test.c \ time_test.c \ tsig_test.c \ update_test.c \ @@ -88,6 +89,7 @@ TARGETS = acl_test@EXEEXT@ \ rdatasetstats_test@EXEEXT@ \ resolver_test@EXEEXT@ \ rsa_test@EXEEXT@ \ + sigs_test@EXEEXT@ \ time_test@EXEEXT@ \ tsig_test@EXEEXT@ \ update_test@EXEEXT@ \ @@ -225,6 +227,11 @@ rsa_test@EXEEXT@: rsa_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} rsa_test.@O@ dnstest.@O@ ${DNSLIBS} \ ${ISCLIBS} ${LIBS} +sigs_test@EXEEXT@: sigs_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + sigs_test.@O@ dnstest.@O@ ${DNSLIBS} \ + ${ISCLIBS} ${LIBS} + time_test@EXEEXT@: time_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ time_test.@O@ dnstest.@O@ ${DNSLIBS} \ diff --git a/lib/dns/tests/sigs_test.c b/lib/dns/tests/sigs_test.c new file mode 100644 index 0000000000..885bbfa00d --- /dev/null +++ b/lib/dns/tests/sigs_test.c @@ -0,0 +1,347 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include + +#include + +#include +#include +#include + +#include "../zone_p.h" + +#include "dnstest.h" + +/*% + * Structure characterizing a single diff tuple in the dns_diff_t structure + * prepared by dns__zone_updatesigs(). + */ +typedef struct { + dns_diffop_t op; + const char *owner; + dns_ttl_t ttl; + const char *type; +} zonediff_t; + +#define ZONEDIFF_SENTINEL { 0, NULL, 0, NULL } + +/*% + * Structure defining a dns__zone_updatesigs() test. + */ +typedef struct { + const char *description; /* test description */ + const zonechange_t *changes; /* array of "raw" zone changes */ + const zonediff_t *zonediff; /* array of "processed" zone changes */ +} updatesigs_test_params_t; + +/*% + * Check whether the 'found' tuple matches the 'expected' tuple. 'found' is + * the 'index'th tuple output by dns__zone_updatesigs() in test 'test'. + */ +static void +compare_tuples(const zonediff_t *expected, dns_difftuple_t *found, + const updatesigs_test_params_t *test, size_t index) +{ + char found_covers[DNS_RDATATYPE_FORMATSIZE] = { }; + char found_type[DNS_RDATATYPE_FORMATSIZE] = { }; + char found_name[DNS_NAME_FORMATSIZE]; + isc_consttextregion_t typeregion; + dns_fixedname_t expected_fname; + dns_rdatatype_t expected_type; + dns_name_t *expected_name; + dns_rdata_rrsig_t rrsig; + isc_buffer_t typebuf; + isc_result_t result; + + REQUIRE(expected != NULL); + REQUIRE(found != NULL); + REQUIRE(index > 0); + + /* + * Check operation. + */ + ATF_CHECK_EQ_MSG(expected->op, found->op, + "test \"%s\": tuple %zu: " + "expected op %d, found %d", + test->description, index, + expected->op, found->op); + + /* + * Check owner name. + */ + expected_name = dns_fixedname_initname(&expected_fname); + result = dns_name_fromstring(expected_name, expected->owner, 0, mctx); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + dns_name_format(&found->name, found_name, sizeof(found_name)); + ATF_CHECK_MSG(dns_name_equal(expected_name, &found->name), + "test \"%s\": tuple %zu: " + "expected owner \"%s\", found \"%s\"", + test->description, index, + expected->owner, found_name); + + /* + * Check TTL. + */ + ATF_CHECK_EQ_MSG(expected->ttl, found->ttl, + "test \"%s\": tuple %zu: " + "expected TTL %u, found %u", + test->description, index, + expected->ttl, found->ttl); + + /* + * Parse expected RR type. + */ + typeregion.base = expected->type; + typeregion.length = strlen(expected->type); + result = dns_rdatatype_fromtext(&expected_type, + (isc_textregion_t*)&typeregion); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + /* + * Format found RR type for reporting purposes. + */ + isc_buffer_init(&typebuf, found_type, sizeof(found_type)); + result = dns_rdatatype_totext(found->rdata.type, &typebuf); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + /* + * Check RR type. + */ + switch (expected->op) { + case DNS_DIFFOP_ADDRESIGN: + case DNS_DIFFOP_DELRESIGN: + /* + * Found tuple must be of type RRSIG. + */ + ATF_CHECK_EQ_MSG(found->rdata.type, dns_rdatatype_rrsig, + "test \"%s\": tuple %zu: " + "expected type RRSIG, found %s", + test->description, index, + found_type); + if (found->rdata.type != dns_rdatatype_rrsig) { + break; + } + /* + * The signature must cover an RRset of type 'expected->type'. + */ + result = dns_rdata_tostruct(&found->rdata, &rrsig, NULL); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + isc_buffer_init(&typebuf, found_covers, sizeof(found_covers)); + result = dns_rdatatype_totext(rrsig.covered, &typebuf); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + ATF_CHECK_EQ_MSG(expected_type, rrsig.covered, + "test \"%s\": tuple %zu: " + "expected RRSIG to cover %s, found covers %s", + test->description, index, + expected->type, found_covers); + break; + default: + /* + * Found tuple must be of type 'expected->type'. + */ + ATF_CHECK_EQ_MSG(expected_type, found->rdata.type, + "test \"%s\": tuple %zu: " + "expected type %s, found %s", + test->description, index, + expected->type, found_type); + break; + } +} + +/*% + * Perform a single dns__zone_updatesigs() test defined in 'test'. All other + * arguments are expected to remain constant between subsequent invocations of + * this function. + */ +static void +updatesigs_test(const updatesigs_test_params_t *test, dns_zone_t *zone, + dns_db_t *db, dst_key_t *zone_keys[], unsigned int nkeys, + isc_stdtime_t now) +{ + size_t tuples_expected, tuples_found, index; + dns_dbversion_t *version = NULL; + dns_diff_t raw_diff, zone_diff; + const zonediff_t *expected; + dns_difftuple_t *found; + isc_result_t result; + + dns__zonediff_t zonediff = { + .diff = &zone_diff, + .offline = ISC_FALSE, + }; + + REQUIRE(test != NULL); + REQUIRE(test->description != NULL); + REQUIRE(test->changes != NULL); + REQUIRE(zone != NULL); + REQUIRE(db != NULL); + REQUIRE(zone_keys != NULL); + + /* + * Create a new version of the zone's database. + */ + result = dns_db_newversion(db, &version); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + /* + * Create a diff representing the supplied changes. + */ + result = dns_test_difffromchanges(&raw_diff, test->changes); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + /* + * Apply the "raw" diff to the new version of the zone's database as + * this is what dns__zone_updatesigs() expects to happen before it is + * called. + */ + dns_diff_apply(&raw_diff, db, version); + + /* + * Initialize the structure dns__zone_updatesigs() will modify. + */ + dns_diff_init(mctx, &zone_diff); + + /* + * Check whether dns__zone_updatesigs() behaves as expected. + */ + result = dns__zone_updatesigs(&raw_diff, db, version, zone_keys, nkeys, + zone, now - 3600, now + 3600, 0, now, + ISC_TRUE, ISC_FALSE, &zonediff); + ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, + "test \"%s\": expected success, got %s", + test->description, isc_result_totext(result)); + ATF_CHECK_MSG(ISC_LIST_EMPTY(raw_diff.tuples), + "test \"%s\": raw diff was not emptied", + test->description); + ATF_CHECK_MSG(!ISC_LIST_EMPTY(zone_diff.tuples), + "test \"%s\": zone diff was not created", + test->description); + + /* + * Ensure that the number of tuples in the zone diff is as expected. + */ + + tuples_expected = 0; + for (expected = test->zonediff; + expected->owner != NULL; + expected++) + { + tuples_expected++; + } + + tuples_found = 0; + for (found = ISC_LIST_HEAD(zone_diff.tuples); + found != NULL; + found = ISC_LIST_NEXT(found, link)) + { + tuples_found++; + } + + ATF_REQUIRE_EQ_MSG(tuples_expected, tuples_found, + "test \"%s\": " + "expected %zu tuples in output, found %zu", + test->description, + tuples_expected, tuples_found); + + /* + * Ensure that every tuple in the zone diff matches expectations. + */ + expected = test->zonediff; + index = 1; + for (found = ISC_LIST_HEAD(zone_diff.tuples); + found != NULL; + found = ISC_LIST_NEXT(found, link)) + { + compare_tuples(expected, found, test, index); + expected++; + index++; + } + + /* + * Apply changes to zone database contents and clean up. + */ + dns_db_closeversion(db, &version, ISC_TRUE); + dns_diff_clear(&zone_diff); + dns_diff_clear(&raw_diff); +} + +ATF_TC(updatesigs); +ATF_TC_HEAD(updatesigs, tc) { + atf_tc_set_md_var(tc, "descr", "dns__zone_updatesigs() tests"); +} +ATF_TC_BODY(updatesigs, tc) { + dst_key_t *zone_keys[DNS_MAXZONEKEYS]; + dns_zone_t *zone = NULL; + dns_db_t *db = NULL; + isc_result_t result; + unsigned int nkeys; + isc_stdtime_t now; + size_t i; + + result = dns_test_begin(NULL, ISC_TRUE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + /* + * Prepare a zone along with its signing keys. + */ + + result = dns_test_makezone("example", &zone, NULL, ISC_FALSE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = dns_test_loaddb(&db, dns_dbtype_zone, "example", + "testdata/master/master18.data"); + ATF_REQUIRE_EQ(result, DNS_R_SEENINCLUDE); + + result = dns_zone_setkeydirectory(zone, "testkeys"); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + isc_stdtime_get(&now); + result = dns__zone_findkeys(zone, db, NULL, now, mctx, DNS_MAXZONEKEYS, + zone_keys, &nkeys); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + ATF_REQUIRE_EQ(nkeys, 2); + + /* + * Define the tests to be run. Note that changes to zone database + * contents introduced by each test are preserved between tests. + */ + + const updatesigs_test_params_t *tests[] = { + NULL, + }; + + /* + * Run tests. + */ + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { + updatesigs_test(tests[i], zone, db, zone_keys, nkeys, now); + } + + /* + * Clean up. + */ + for (i = 0; i < nkeys; i++) { + dst_key_free(&zone_keys[i]); + } + dns_db_detach(&db); + dns_zone_detach(&zone); + + dns_test_end(); +} + +ATF_TP_ADD_TCS(tp) { + ATF_TP_ADD_TC(tp, updatesigs); + + return (atf_no_error()); +} diff --git a/lib/dns/tests/testdata/master/master18.data b/lib/dns/tests/testdata/master/master18.data new file mode 100644 index 0000000000..dddf04e3bf --- /dev/null +++ b/lib/dns/tests/testdata/master/master18.data @@ -0,0 +1,10 @@ +$TTL 1000 +@ in soa localhost. postmaster.localhost. ( + 1993050801 ;serial + 3600 ;refresh + 1800 ;retry + 604800 ;expiration + 3600 ) ;minimum + +$INCLUDE "testkeys/Kexample.+008+20386.key"; +$INCLUDE "testkeys/Kexample.+008+37464.key"; diff --git a/lib/dns/tests/testkeys/Kexample.+008+20386.key b/lib/dns/tests/testkeys/Kexample.+008+20386.key new file mode 100644 index 0000000000..3404dcaec4 --- /dev/null +++ b/lib/dns/tests/testkeys/Kexample.+008+20386.key @@ -0,0 +1,5 @@ +; This is a key-signing key, keyid 20386, for example. +; Created: 20000101000000 (Sat Jan 1 00:00:00 2000) +; Publish: 20000101000000 (Sat Jan 1 00:00:00 2000) +; Activate: 20000101000000 (Sat Jan 1 00:00:00 2000) +example. IN DNSKEY 257 3 8 AwEAAZd7/hBRvMooz0sepkD/2r3Bp021f8lGzDj6sZEVbg1hcqZTzURc eGkS541wyOqjvJv2KBi5qLLE2HthmexmOBycjTQ7EiKd1P9bE8RgF8Et j73X/CHLiX6YL7cb93TXWiUvbRh4E6D2URgOmxMdMOXTuCvjvDaGVCOt Jc77UUosuBeurZzP8g8t/zccAUTzu2cdRyI5/ZxOBfJaDtc9TlRdWsaN Af+nT0C14ccH7QVlKjjaYV4lXueruDW3yTTzu9bQ1ikgegsCLi/tcD/1 dWTOI9whV06szs+ouhuJkZuhIjrGDtOHCpjPjIxOOrIZceU1YSY30kAR QNVzshJqyx8= diff --git a/lib/dns/tests/testkeys/Kexample.+008+20386.private b/lib/dns/tests/testkeys/Kexample.+008+20386.private new file mode 100644 index 0000000000..d8cff93d60 --- /dev/null +++ b/lib/dns/tests/testkeys/Kexample.+008+20386.private @@ -0,0 +1,13 @@ +Private-key-format: v1.3 +Algorithm: 8 (RSASHA256) +Modulus: l3v+EFG8yijPSx6mQP/avcGnTbV/yUbMOPqxkRVuDWFyplPNRFx4aRLnjXDI6qO8m/YoGLmossTYe2GZ7GY4HJyNNDsSIp3U/1sTxGAXwS2Pvdf8IcuJfpgvtxv3dNdaJS9tGHgToPZRGA6bEx0w5dO4K+O8NoZUI60lzvtRSiy4F66tnM/yDy3/NxwBRPO7Zx1HIjn9nE4F8loO1z1OVF1axo0B/6dPQLXhxwftBWUqONphXiVe56u4NbfJNPO71tDWKSB6CwIuL+1wP/V1ZM4j3CFXTqzOz6i6G4mRm6EiOsYO04cKmM+MjE46shlx5TVhJjfSQBFA1XOyEmrLHw== +PublicExponent: AQAB +PrivateExponent: aSkynrGfldfuz/9e+xCjEcg2FMRDCb+UVpnyWv29gJx9sunKPgLTtF3jUVVSpVE1xi+EdmWsry3n+v8uk+YCXhpwDCpV1KItE3huqIzs8LZoaypdZjieIrwTo9JOX1aAxf++hJYXSk60zTaWgRZqs6He4Nkf99oY3wt8i8v8CrkfQy76K/qK9xUVv5GHrEZzCGLfLv77eqDab/J84ANxc0kUtQvgt2/JTHofXmcA6/YDh5PWB8KRw1PjQTck61/xIgfI6ky/yIF1riCQCYXwTv7jcmMV/QvQ+dfN+HZ2CSGp7xcH2Yxe9OhAY823ZkmkOQ2YZPjIj6dEoRMmSiaagQ== +Prime1: x2GMnpRPwvUhM+yPRa7nh5Jjl4mbofeOtVrxe1hEVy8l2UGFh+FDZCbyoLRNUTYDji00NHpGtmcAyoY9pLdOn7ci4zqGVnNJcIY75Ie4p6J7pPfDh9d+AGtJ5NpNhr1sjD0bFncJC2FGY9vj4eC0CkatMu/Qovrd2FwZ8VpDsAk= +Prime2: woB8MYsEfSYGD0hZGtmgK6UQ+Oo9smxdPmahLYXnLSAdqtqZbZX+ABk/kFduT+XwlHOXmp3HMmUtQTRZBaQyBrsFWfWjOGevByEsT9aLQSZOEgnqy4xrc9XNwDs4/WkrEgw/TOVnZYdaCyLxsFl4bpTX8Fj3yVqg/tJvuUMWG+c= +Exponent1: iQO7a9rF+VcVSyZ8yslIaL0r3Z5+Kk8CbhSiMD5XMIbA/sztI5SlCDVPtSpSm8V/qfvcjVeeMokUXRjlUcV6rX1f50F3wf8V79L/Y6v1NJYPXC273CU1fLo+HJv8fOS9rJ3teIGy4HQnuEYLE1WkxA8PxRpSiT3WqHGajmaWb2k= +Exponent2: elMWSI5Wz2KXkwr8Rz+xVWGl7/ZZwRoX9oPTQG8jeiTlo6uBrQMVUPiQGnZyQTuq96JPKYWrXs11DbofdsXSVJtQfUhYU8QZtxEs7jVPNTUjCoNEMKnqdlpz4T8d03pOBTbApNruEVNz1OcwO6m5bUqdGGLLy838zOaKL2i6wec= +Coefficient: q2mejAmT3A4H2C0rT1hm8XQFuISHjAAEyM9t09Q8tEeQ0lHi4gMVA3bXoAn9U21eBkFQDwvyB0vqlVSGgRqHovOKx9uXAU9eoDxGcJsFlGsM0aUsUjGVXv5kVmaw8a5PHBbvYAbgAZUmKqrVF0PWD3o+/DbzP9PCmlJcqxoAulU= +Created: 20000101000000 +Publish: 20000101000000 +Activate: 20000101000000 diff --git a/lib/dns/tests/testkeys/Kexample.+008+37464.key b/lib/dns/tests/testkeys/Kexample.+008+37464.key new file mode 100644 index 0000000000..3dd0619c5e --- /dev/null +++ b/lib/dns/tests/testkeys/Kexample.+008+37464.key @@ -0,0 +1,5 @@ +; This is a zone-signing key, keyid 37464, for example. +; Created: 20000101000000 (Sat Jan 1 00:00:00 2000) +; Publish: 20000101000000 (Sat Jan 1 00:00:00 2000) +; Activate: 20000101000000 (Sat Jan 1 00:00:00 2000) +example. IN DNSKEY 256 3 8 AwEAAbxHOF8G0xw9ekCodhL8KivuZ3o0jmGlycLiXBjBN8c5R5fjLjUh D0gy3IDbDC+kLaPhHGF/MwrSEjrgSowxZ8nrxDzsq5ZdpeUsYaNrbQEY /mqf35T/9/Ulm4v06x58v/NTugWd05Xq04aAyfm7EViyGFzmVOVfPnll h9xQtvWEWoRWPseFw+dY5/nc/+xB/IsQMihoH2rO+cek/lsP3R9DsHCG RbQ/ks/+rrp6/O+QJZyZrzsONl7mlMDXNy3Pz9J4qMW2W6Mz702LN324 7/9UsetDGGbuZfrCLMpKWXzdsJm36DOk4aMooS9111plfXaXQgQNcL5G 021utpTau+8= diff --git a/lib/dns/tests/testkeys/Kexample.+008+37464.private b/lib/dns/tests/testkeys/Kexample.+008+37464.private new file mode 100644 index 0000000000..ecc2ad0db0 --- /dev/null +++ b/lib/dns/tests/testkeys/Kexample.+008+37464.private @@ -0,0 +1,13 @@ +Private-key-format: v1.3 +Algorithm: 8 (RSASHA256) +Modulus: vEc4XwbTHD16QKh2EvwqK+5nejSOYaXJwuJcGME3xzlHl+MuNSEPSDLcgNsML6Qto+EcYX8zCtISOuBKjDFnyevEPOyrll2l5Sxho2ttARj+ap/flP/39SWbi/TrHny/81O6BZ3TlerThoDJ+bsRWLIYXOZU5V8+eWWH3FC29YRahFY+x4XD51jn+dz/7EH8ixAyKGgfas75x6T+Ww/dH0OwcIZFtD+Sz/6uunr875AlnJmvOw42XuaUwNc3Lc/P0nioxbZbozPvTYs3fbjv/1Sx60MYZu5l+sIsykpZfN2wmbfoM6ThoyihL3XXWmV9dpdCBA1wvkbTbW62lNq77w== +PublicExponent: AQAB +PrivateExponent: AhR3VvVoV6OGOjiiNUt728hidEMoX4PJWtHNWqinyRek5tSnqgaXeKC3NuU0mUIjDvBps9oH4lK3yNa5fBr/nodwP4wNyTd3obR/z6JcLersxJjHi4nYX2ju8vjdsBSIulNudqlrsPhLJe0+Tff3FRfClSQmQ/JtakHo4lIx8zxiOJY8aWFeHGdWJDkAf6NStt3eVYyOyAwISfv3muaGPZKShiIOfLyTvqFqzwYFgdTWmvFqTdwgjIMc5XAwqw73WP2BPCN+fdCiMtrw0fCrhWzw/gfMJBHdOPH0diUZysAJhM0vdVKQzEi/g3YOo00fahZiPzaxNtZnLNj2mA54YQ== +Prime1: 5YpfVjEtL1owW9gSFbIMx65POr+fiktxirgy1bc5fSsVqUgG6zhbaN/VpWcNZG0Zg5xd6S7C8V3djGlnJN8wZIyjIh7+Z3WWjqbOD9oY7rC1fR+W0OvbCmZiEzOpRJ5qoMOh1MzkkanhMy0/ICpaa8eQ9zEb80oTIQpFgoLn7K0= +Prime2: 0fs3ncL5/2qzq2dmPXLYcOfc1EGSuESO0VpREP8EpTkyPKeVw5LaF9TgZRqPWlRf2T0LPoZ766xLAn090u0pLQ5fWM96NMas7kS+rxtRssat6MiQo3YfoU3ysk3xuPzrMBHyn/N42CjSG+bJEToHR7V16KsCT6dBIPkI3tj/Yos= +Exponent1: Bdsp44ENrg+W/EDe9T69pLqFuvH4mAaktu1MHre198OJoe/8fTPK4ToUsUuXw+Akrn7mxnQy9QV4CYUG5KHtEiOkZdJ0mx8c4DbROwZNbImFl9OefWYHCJTkG6lNwDpqbf+PuWYgzraO0EdvPNrXw7grsqLGG8bgBg/FBjdgw2E= +Exponent2: uV1pxW0fwGhzX3aR/ODrTRCCEyYn3V84LHvsYHKfqTOKs5zFSrbSrIMR7G676ePeESogSPvzXSLlvLbO4urVlJ7BcOcHXJuegWBSbMZTItzdHUgg1wwp8/2Zp+nC36j1/aN6adVG8ptmj5b2HKz7TERWaCS+j454oiD1wbQSDu0= +Coefficient: JO6RxBIaoEd/Z4ITcsYT8TslP1KmIuAqdhMt3FSpqeogUDut7f3FZIEyNi4wsrSK5peIQSVmO2pQLupS+eRIPHXZ1vh5kcFAsgd7XBb7Fvsg26/WSjhB4wjx+wgWzVomK0519pfdtH854fePWPkdDKtLNL2zh0APne3GjwrbNEM= +Created: 20000101000000 +Publish: 20000101000000 +Activate: 20000101000000 diff --git a/util/copyrights b/util/copyrights index 2779a8070a..888aa61fbe 100644 --- a/util/copyrights +++ b/util/copyrights @@ -3336,6 +3336,7 @@ ./lib/dns/tests/rdatasetstats_test.c C 2012,2015,2016,2018 ./lib/dns/tests/resolver_test.c C 2018 ./lib/dns/tests/rsa_test.c C 2016,2018 +./lib/dns/tests/sigs_test.c C 2018 ./lib/dns/tests/testdata/db/data.db ZONE 2018 ./lib/dns/tests/testdata/dbiterator/zone1.data ZONE 2011,2012,2016,2018 ./lib/dns/tests/testdata/dbiterator/zone2.data X 2011,2018 @@ -3369,6 +3370,7 @@ ./lib/dns/tests/testdata/master/master15.data X 2012,2018 ./lib/dns/tests/testdata/master/master16.data X 2012,2018 ./lib/dns/tests/testdata/master/master17.data X 2012,2018 +./lib/dns/tests/testdata/master/master18.data X 2018 ./lib/dns/tests/testdata/master/master2.data X 2011,2018 ./lib/dns/tests/testdata/master/master3.data X 2011,2018 ./lib/dns/tests/testdata/master/master4.data X 2011,2018 @@ -3383,6 +3385,10 @@ ./lib/dns/tests/testdata/nsec3/min-1024.db ZONE 2012,2016,2018 ./lib/dns/tests/testdata/nsec3/min-2048.db ZONE 2012,2016,2018 ./lib/dns/tests/testdata/zt/zone1.db ZONE 2011,2012,2016,2018 +./lib/dns/tests/testkeys/Kexample.+008+20386.key X 2018 +./lib/dns/tests/testkeys/Kexample.+008+20386.private X 2018 +./lib/dns/tests/testkeys/Kexample.+008+37464.key X 2018 +./lib/dns/tests/testkeys/Kexample.+008+37464.private X 2018 ./lib/dns/tests/time_test.c C 2011,2012,2016,2018 ./lib/dns/tests/tsig_test.c C 2017,2018 ./lib/dns/tests/update_test.c C 2011,2012,2014,2016,2017,2018 From 8b9d2c27b4b96bd0f981e8a8fb608a3bfcdb1e0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Tue, 13 Mar 2018 14:06:13 +0100 Subject: [PATCH 09/10] Define basic test cases for dns__zone_updatesigs() Add some basic test cases ensuring dns__zone_updatesigs() behaves as expected. --- lib/dns/tests/sigs_test.c | 98 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/lib/dns/tests/sigs_test.c b/lib/dns/tests/sigs_test.c index 885bbfa00d..90f513aa62 100644 --- a/lib/dns/tests/sigs_test.c +++ b/lib/dns/tests/sigs_test.c @@ -317,8 +317,104 @@ ATF_TC_BODY(updatesigs, tc) { * contents introduced by each test are preserved between tests. */ + const zonechange_t changes_add[] = { + { DNS_DIFFOP_ADD, "foo.example", 300, "TXT", "foo" }, + { DNS_DIFFOP_ADD, "bar.example", 600, "TXT", "bar" }, + ZONECHANGE_SENTINEL, + }; + const zonediff_t zonediff_add[] = { + { DNS_DIFFOP_ADDRESIGN, "foo.example", 300, "TXT" }, + { DNS_DIFFOP_ADD, "foo.example", 300, "TXT" }, + { DNS_DIFFOP_ADDRESIGN, "bar.example", 600, "TXT" }, + { DNS_DIFFOP_ADD, "bar.example", 600, "TXT" }, + ZONEDIFF_SENTINEL, + }; + const updatesigs_test_params_t test_add = { + .description = "add new RRsets", + .changes = changes_add, + .zonediff = zonediff_add, + }; + + const zonechange_t changes_append[] = { + { DNS_DIFFOP_ADD, "foo.example", 300, "TXT", "foo1" }, + { DNS_DIFFOP_ADD, "foo.example", 300, "TXT", "foo2" }, + ZONECHANGE_SENTINEL, + }; + const zonediff_t zonediff_append[] = { + { DNS_DIFFOP_DELRESIGN, "foo.example", 300, "TXT" }, + { DNS_DIFFOP_ADDRESIGN, "foo.example", 300, "TXT" }, + { DNS_DIFFOP_ADD, "foo.example", 300, "TXT" }, + { DNS_DIFFOP_ADD, "foo.example", 300, "TXT" }, + ZONEDIFF_SENTINEL, + }; + const updatesigs_test_params_t test_append = { + .description = "append multiple RRs to an existing RRset", + .changes = changes_append, + .zonediff = zonediff_append, + }; + + const zonechange_t changes_replace[] = { + { DNS_DIFFOP_DEL, "bar.example", 600, "TXT", "bar" }, + { DNS_DIFFOP_ADD, "bar.example", 600, "TXT", "rab" }, + ZONECHANGE_SENTINEL, + }; + const zonediff_t zonediff_replace[] = { + { DNS_DIFFOP_DELRESIGN, "bar.example", 600, "TXT" }, + { DNS_DIFFOP_ADDRESIGN, "bar.example", 600, "TXT" }, + { DNS_DIFFOP_DEL, "bar.example", 600, "TXT" }, + { DNS_DIFFOP_ADD, "bar.example", 600, "TXT" }, + ZONEDIFF_SENTINEL, + }; + const updatesigs_test_params_t test_replace = { + .description = "replace an existing RRset", + .changes = changes_replace, + .zonediff = zonediff_replace, + }; + + const zonechange_t changes_delete[] = { + { DNS_DIFFOP_DEL, "bar.example", 600, "TXT", "rab" }, + ZONECHANGE_SENTINEL, + }; + const zonediff_t zonediff_delete[] = { + { DNS_DIFFOP_DELRESIGN, "bar.example", 600, "TXT" }, + { DNS_DIFFOP_DEL, "bar.example", 600, "TXT" }, + ZONEDIFF_SENTINEL, + }; + const updatesigs_test_params_t test_delete = { + .description = "delete an existing RRset", + .changes = changes_delete, + .zonediff = zonediff_delete, + }; + + const zonechange_t changes_mixed[] = { + { DNS_DIFFOP_ADD, "baz.example", 900, "TXT", "baz1" }, + { DNS_DIFFOP_ADD, "baz.example", 900, "A", "127.0.0.1" }, + { DNS_DIFFOP_ADD, "baz.example", 900, "TXT", "baz2" }, + { DNS_DIFFOP_ADD, "baz.example", 900, "AAAA", "::1" }, + ZONECHANGE_SENTINEL, + }; + const zonediff_t zonediff_mixed[] = { + { DNS_DIFFOP_ADDRESIGN, "baz.example", 900, "TXT" }, + { DNS_DIFFOP_ADD, "baz.example", 900, "TXT" }, + { DNS_DIFFOP_ADD, "baz.example", 900, "TXT" }, + { DNS_DIFFOP_ADDRESIGN, "baz.example", 900, "A" }, + { DNS_DIFFOP_ADD, "baz.example", 900, "A" }, + { DNS_DIFFOP_ADDRESIGN, "baz.example", 900, "AAAA" }, + { DNS_DIFFOP_ADD, "baz.example", 900, "AAAA" }, + ZONEDIFF_SENTINEL, + }; + const updatesigs_test_params_t test_mixed = { + .description = "add different RRsets with common owner name", + .changes = changes_mixed, + .zonediff = zonediff_mixed, + }; + const updatesigs_test_params_t *tests[] = { - NULL, + &test_add, + &test_append, + &test_replace, + &test_delete, + &test_mixed, }; /* From 4885809eb95ec8c5392fa4815abfaf140bf3a351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Tue, 13 Mar 2018 14:06:15 +0100 Subject: [PATCH 10/10] Add CHANGES entry 4939. [test] Add basic unit tests for update_sigs(). [GL #135] --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index ea4ff593b3..5f6e79aaed 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,5 @@ +4939. [test] Add basic unit tests for update_sigs(). [GL #135] + 4938. [placeholder] 4937. [func] Remove support for OpenSSL < 1.0.0 [GL #191]