1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7  *
8  * See the COPYRIGHT file distributed with this work for additional
9  * information regarding copyright ownership.
10  */
11 
12 #if HAVE_CMOCKA
13 
14 #include <sched.h> /* IWYU pragma: keep */
15 #include <setjmp.h>
16 #include <stdarg.h>
17 #include <stddef.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 
22 #define UNIT_TESTING
23 #include <cmocka.h>
24 
25 #include <isc/string.h>
26 #include <isc/util.h>
27 
28 #include <dns/db.h>
29 #include <dns/nsec3.h>
30 
31 #include "dnstest.h"
32 
33 static int
_setup(void ** state)34 _setup(void **state) {
35 	isc_result_t result;
36 
37 	UNUSED(state);
38 
39 	result = dns_test_begin(NULL, false);
40 	assert_int_equal(result, ISC_R_SUCCESS);
41 
42 	return (0);
43 }
44 
45 static int
_teardown(void ** state)46 _teardown(void **state) {
47 	UNUSED(state);
48 
49 	dns_test_end();
50 
51 	return (0);
52 }
53 
54 static void
iteration_test(const char * file,unsigned int expected)55 iteration_test(const char *file, unsigned int expected) {
56 	isc_result_t result;
57 	dns_db_t *db = NULL;
58 	unsigned int iterations;
59 
60 	result = dns_test_loaddb(&db, dns_dbtype_zone, "test", file);
61 	assert_int_equal(result, ISC_R_SUCCESS);
62 
63 	result = dns_nsec3_maxiterations(db, NULL, dt_mctx, &iterations);
64 	assert_int_equal(result, ISC_R_SUCCESS);
65 
66 	assert_int_equal(iterations, expected);
67 
68 	dns_db_detach(&db);
69 }
70 
71 /*%
72  * Structure containing parameters for nsec3param_salttotext_test().
73  */
74 typedef struct {
75 	const char *nsec3param_text; /* NSEC3PARAM RDATA in text form */
76 	const char *expected_salt;   /* string expected in target buffer */
77 } nsec3param_salttotext_test_params_t;
78 
79 /*%
80  * Check whether dns_nsec3param_salttotext() handles supplied text form
81  * NSEC3PARAM RDATA correctly: test whether the result of calling the former is
82  * as expected and whether it properly checks available buffer space.
83  *
84  * Assumes supplied text form NSEC3PARAM RDATA is valid as testing handling of
85  * invalid NSEC3PARAM RDATA is out of scope of this unit test.
86  */
87 static void
nsec3param_salttotext_test(const nsec3param_salttotext_test_params_t * params)88 nsec3param_salttotext_test(const nsec3param_salttotext_test_params_t *params) {
89 	dns_rdata_t rdata = DNS_RDATA_INIT;
90 	dns_rdata_nsec3param_t nsec3param;
91 	unsigned char buf[1024];
92 	isc_result_t result;
93 	char salt[64];
94 	size_t length;
95 
96 	/*
97 	 * Prepare a dns_rdata_nsec3param_t structure for testing.
98 	 */
99 	result = dns_test_rdatafromstring(
100 		&rdata, dns_rdataclass_in, dns_rdatatype_nsec3param, buf,
101 		sizeof(buf), params->nsec3param_text, false);
102 	assert_int_equal(result, ISC_R_SUCCESS);
103 	result = dns_rdata_tostruct(&rdata, &nsec3param, NULL);
104 	assert_int_equal(result, ISC_R_SUCCESS);
105 
106 	/*
107 	 * Check typical use.
108 	 */
109 	result = dns_nsec3param_salttotext(&nsec3param, salt, sizeof(salt));
110 	assert_int_equal(result, ISC_R_SUCCESS);
111 	assert_string_equal(salt, params->expected_salt);
112 
113 	/*
114 	 * Ensure available space in the buffer is checked before the salt is
115 	 * printed to it and that the amount of space checked for includes the
116 	 * terminating NULL byte.
117 	 */
118 	length = strlen(params->expected_salt);
119 	assert_true(length < sizeof(salt) - 1); /* prevent buffer overwrite */
120 	assert_true(length > 0U);		/* prevent length underflow */
121 
122 	result = dns_nsec3param_salttotext(&nsec3param, salt, length - 1);
123 	assert_int_equal(result, ISC_R_NOSPACE);
124 
125 	result = dns_nsec3param_salttotext(&nsec3param, salt, length);
126 	assert_int_equal(result, ISC_R_NOSPACE);
127 
128 	result = dns_nsec3param_salttotext(&nsec3param, salt, length + 1);
129 	assert_int_equal(result, ISC_R_SUCCESS);
130 }
131 
132 /*
133  * check that appropriate max iterations is returned for different
134  * key size mixes
135  */
136 static void
max_iterations(void ** state)137 max_iterations(void **state) {
138 	UNUSED(state);
139 
140 	iteration_test("testdata/nsec3/1024.db", 150);
141 	iteration_test("testdata/nsec3/2048.db", 500);
142 	iteration_test("testdata/nsec3/4096.db", 2500);
143 	iteration_test("testdata/nsec3/min-1024.db", 150);
144 	iteration_test("testdata/nsec3/min-2048.db", 500);
145 }
146 
147 /* check dns_nsec3param_salttotext() */
148 static void
nsec3param_salttotext(void ** state)149 nsec3param_salttotext(void **state) {
150 	size_t i;
151 
152 	const nsec3param_salttotext_test_params_t tests[] = {
153 		/*
154 		 * Tests with non-empty salts.
155 		 */
156 		{ "0 0 10 0123456789abcdef", "0123456789ABCDEF" },
157 		{ "0 1 11 0123456789abcdef", "0123456789ABCDEF" },
158 		{ "1 0 12 42", "42" },
159 		{ "1 1 13 42", "42" },
160 		/*
161 		 * Test with empty salt.
162 		 */
163 		{ "0 0 0 -", "-" },
164 	};
165 
166 	UNUSED(state);
167 
168 	for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
169 		nsec3param_salttotext_test(&tests[i]);
170 	}
171 }
172 
173 int
main(void)174 main(void) {
175 	const struct CMUnitTest tests[] = {
176 		cmocka_unit_test_setup_teardown(max_iterations, _setup,
177 						_teardown),
178 		cmocka_unit_test_setup_teardown(nsec3param_salttotext, _setup,
179 						_teardown),
180 	};
181 
182 	return (cmocka_run_group_tests(tests, NULL, NULL));
183 }
184 
185 #else /* HAVE_CMOCKA */
186 
187 #include <stdio.h>
188 
189 int
main(void)190 main(void) {
191 	printf("1..0 # Skipped: cmocka not available\n");
192 	return (0);
193 }
194 
195 #endif /* if HAVE_CMOCKA */
196