1 /*  Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2 
3     This program is free software: you can redistribute it and/or modify
4     it under the terms of the GNU General Public License as published by
5     the Free Software Foundation, either version 3 of the License, or
6     (at your option) any later version.
7 
8     This program is distributed in the hope that it will be useful,
9     but WITHOUT ANY WARRANTY; without even the implied warranty of
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11     GNU General Public License for more details.
12 
13     You should have received a copy of the GNU General Public License
14     along with this program.  If not, see <https://www.gnu.org/licenses/>.
15  */
16 
17 #include <tap/basic.h>
18 #include <assert.h>
19 #include <stdbool.h>
20 #include <string.h>
21 #include <unistd.h>
22 
23 #include "libknot/errcode.h"
24 #include "libknot/tsig.h"
25 
key_is_eq(const knot_tsig_key_t * a,const knot_tsig_key_t * b)26 static bool key_is_eq(const knot_tsig_key_t *a, const knot_tsig_key_t *b)
27 {
28 	if (a == NULL && b == NULL) {
29 		return true;
30 	}
31 
32 	if (a == NULL || b == NULL) {
33 		return false;
34 	}
35 
36 	return a->algorithm == b->algorithm &&
37 	       knot_dname_is_equal(a->name, b->name) &&
38 	       dnssec_binary_cmp(&a->secret, &b->secret) == 0;
39 }
40 
41 #define test_function(function, msg, expected, ...) \
42 	knot_tsig_key_t key = { 0 }; \
43 	int r = function(&key, __VA_ARGS__); \
44 	ok((r != KNOT_EOK && expected == NULL) || \
45 	   (r == KNOT_EOK && key_is_eq(&key, expected)), \
46 	   "%s: %s", #function, msg); \
47 	knot_tsig_key_deinit(&key);
48 
test_init(const char * msg,const knot_tsig_key_t * expected,const char * algo,const char * name,const char * secret)49 static void test_init(const char *msg, const knot_tsig_key_t *expected,
50                       const char *algo, const char *name, const char *secret)
51 {
52 	test_function(knot_tsig_key_init, msg, expected, algo, name, secret);
53 }
54 
test_init_str(const char * msg,const knot_tsig_key_t * expected,const char * params)55 static void test_init_str(const char *msg, const knot_tsig_key_t *expected,
56                           const char *params)
57 {
58 	test_function(knot_tsig_key_init_str, msg, expected, params);
59 }
60 
test_init_file(const char * msg,const knot_tsig_key_t * expected,const char * filename)61 static void test_init_file(const char *msg, const knot_tsig_key_t *expected,
62                            const char *filename)
63 {
64 	test_function(knot_tsig_key_init_file, msg, expected, filename);
65 }
66 
test_init_file_content(const char * msg,const knot_tsig_key_t * expected,const char * content)67 static void test_init_file_content(const char *msg,
68                                    const knot_tsig_key_t *expected,
69                                    const char *content)
70 {
71 	char filename[] = "testkey.XXXXXX";
72 
73 	int fd = mkstemp(filename);
74 	if (fd == -1) {
75 		bail("failed to create temporary file");
76 		return;
77 	}
78 
79 	ok(write(fd, content, strlen(content)) != -1, "file write");
80 	close(fd);
81 
82 	test_init_file(msg, expected, filename);
83 
84 	unlink(filename);
85 }
86 
main(int argc,char * argv[])87 int main(int argc, char *argv[])
88 {
89 	plan_lazy();
90 
91 	// initialization from parameters
92 
93 	test_init("missing name", NULL, "hmac-md5", NULL, "Wg==");
94 	test_init("missing secret", NULL, "hmac-md5", "name", NULL);
95 	test_init("invalid HMAC", NULL, "hmac-sha11", "name", "Wg==");
96 	{
97 		static const knot_tsig_key_t key = {
98 			.algorithm = DNSSEC_TSIG_HMAC_SHA256,
99 			.name = (uint8_t *)"\x3""key""\x4""name",
100 			.secret.size = 1,
101 			.secret.data = (uint8_t *)"\x5a"
102 		};
103 		test_init("default algorithm", &key, NULL, "key.name", "Wg==");
104 	}
105 	{
106 		static const knot_tsig_key_t key = {
107 			.algorithm = DNSSEC_TSIG_HMAC_SHA1,
108 			.name = (uint8_t *)"\x4""knot""\x3""dns",
109 			.secret.size = 6,
110 			.secret.data = (uint8_t *)"secret"
111 		};
112 		test_init("sha1", &key, "hmac-sha1", "knot.dns.", "c2VjcmV0");
113 	}
114 
115 	// initialization from string
116 
117 	test_init_str("missing value", NULL, NULL);
118 	test_init_str("malformed", NULL, "this is malformed");
119 	test_init_str("invalid HMAC", NULL, "hmac-sha51299:key:Wg==");
120 	{
121 		static const knot_tsig_key_t key = {
122 			.algorithm = DNSSEC_TSIG_HMAC_SHA256,
123 			.name = (uint8_t *)"\x4""tsig""\x3""key",
124 			.secret.size = 9,
125 			.secret.data = (uint8_t *)"bananakey"
126 		};
127 		test_init_str("default algorithm", &key, "tsig.key:YmFuYW5ha2V5");
128 	}
129 	{
130 		static const knot_tsig_key_t key = {
131 			.algorithm = DNSSEC_TSIG_HMAC_SHA384,
132 			.name = (uint8_t *)"\x6""strong""\x3""key",
133 			.secret.size = 8,
134 			.secret.data = (uint8_t *)"applekey"
135 		};
136 		test_init_str("sha384", &key, "hmac-sha384:strong.KEY:YXBwbGVrZXk=");
137 	}
138 
139 	// initialization from a file
140 
141 	test_init_file("no filename", NULL, NULL);
142 	test_init_file("not-existing", NULL, "/this-really-should-not-exist");
143 	test_init_file_content("malformed content", NULL, "malformed\n");
144 	{
145 		static const knot_tsig_key_t key = {
146 			.algorithm = DNSSEC_TSIG_HMAC_SHA512,
147 			.name = (uint8_t *)"\x6""django""\x3""one",
148 			.secret.size = 40,
149 			.secret.data = (uint8_t *)"Who's that stumbling around in the dark?"
150 		};
151 		test_init_file_content("sha512", &key,
152 		                       "hmac-sha512:django.one:V2hvJ3MgdGhhdCB"
153 		                       "zdHVtYmxpbmcgYXJvdW5kIGluIHRoZSBkYXJrP"
154 		                       "w==\n\n\n");
155 	}
156 	{
157 		static const knot_tsig_key_t key = {
158 			.algorithm = DNSSEC_TSIG_HMAC_SHA512,
159 			.name = (uint8_t *)"\x6""django""\x3""two",
160 			.secret.size = 22,
161 			.secret.data = (uint8_t *)"Prepare to get winged!"
162 		};
163 		test_init_file_content("sha512 without newline", &key,
164 		                       "hmac-sha512:django.two:UHJlcGFyZSB0byB"
165 		                       "nZXQgd2luZ2VkIQ==");
166 	}
167 	{
168 		static const knot_tsig_key_t key = {
169 			.algorithm = DNSSEC_TSIG_HMAC_SHA1,
170 			.name = (uint8_t *)"\x4""test",
171 			.secret.size = 1,
172 			.secret.data = (uint8_t *)"\x5a"
173 		};
174 		test_init_file_content("leading and trailing white spaces", &key,
175 		                       "\thmac-sha1:test:Wg== \n");
176 	}
177 
178 	// tsig key duplication
179 
180 	{
181 		static const knot_tsig_key_t key = {
182 			.algorithm = DNSSEC_TSIG_HMAC_SHA1,
183 			.name = (uint8_t *)"\x4""copy""\x2""me",
184 			.secret.size = 6,
185 			.secret.data = (uint8_t *)"orange"
186 		};
187 
188 		knot_tsig_key_t copy = { 0 };
189 		int r;
190 
191 		r = knot_tsig_key_copy(NULL, &key);
192 		ok(r != KNOT_EOK, "knot_tsig_key_copy: no destination");
193 		r = knot_tsig_key_copy(&copy, NULL);
194 		ok(r != KNOT_EOK, "knot_tsig_key_copy: no source");
195 		r = knot_tsig_key_copy(&copy, &key);
196 		ok(r == KNOT_EOK && key_is_eq(&copy, &key) &&
197 		   copy.secret.data != key.secret.data && copy.name != key.name,
198 		   "knot_tsig_key_copy: simple copy");
199 
200 		knot_tsig_key_deinit(&copy);
201 	}
202 
203 	return 0;
204 }
205