1/*
2 * Copyright (C) 2004, 2005, 2007, 2009, 2011  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2001  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id: keycreate.c,v 1.20 2011/01/11 23:47:13 tbox Exp $ */
19
20#include <config.h>
21
22#include <stdlib.h>
23#include <string.h>
24
25#include <isc/app.h>
26#include <isc/base64.h>
27#include <isc/entropy.h>
28#include <isc/hash.h>
29#include <isc/log.h>
30#include <isc/mem.h>
31#include <isc/sockaddr.h>
32#include <isc/socket.h>
33#include <isc/task.h>
34#include <isc/timer.h>
35#include <isc/util.h>
36
37#include <dns/dispatch.h>
38#include <dns/fixedname.h>
39#include <dns/keyvalues.h>
40#include <dns/message.h>
41#include <dns/name.h>
42#include <dns/request.h>
43#include <dns/result.h>
44#include <dns/tkey.h>
45#include <dns/tsig.h>
46#include <dns/view.h>
47
48#include <dst/result.h>
49
50#define CHECK(str, x) { \
51	if ((x) != ISC_R_SUCCESS) { \
52		fprintf(stderr, "I:%s: %s\n", (str), isc_result_totext(x)); \
53		exit(-1); \
54	} \
55}
56
57#define RUNCHECK(x) RUNTIME_CHECK((x) == ISC_R_SUCCESS)
58
59#define PORT 5300
60#define TIMEOUT 30
61
62static dst_key_t *ourkey;
63static isc_mem_t *mctx;
64static dns_tsigkey_t *tsigkey, *initialkey;
65static dns_tsig_keyring_t *ring;
66static unsigned char noncedata[16];
67static isc_buffer_t nonce;
68static dns_requestmgr_t *requestmgr;
69static const char *ownername_str = ".";
70
71static void
72recvquery(isc_task_t *task, isc_event_t *event) {
73	dns_requestevent_t *reqev = (dns_requestevent_t *)event;
74	isc_result_t result;
75	dns_message_t *query, *response;
76	char keyname[256];
77	isc_buffer_t keynamebuf;
78	int type;
79
80	UNUSED(task);
81
82	REQUIRE(reqev != NULL);
83
84	if (reqev->result != ISC_R_SUCCESS) {
85		fprintf(stderr, "I:request event result: %s\n",
86			isc_result_totext(reqev->result));
87		exit(-1);
88	}
89
90	query = reqev->ev_arg;
91
92	response = NULL;
93	result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response);
94	CHECK("dns_message_create", result);
95
96	result = dns_request_getresponse(reqev->request, response,
97					 DNS_MESSAGEPARSE_PRESERVEORDER);
98	CHECK("dns_request_getresponse", result);
99
100	if (response->rcode != dns_rcode_noerror) {
101		result = ISC_RESULTCLASS_DNSRCODE + response->rcode;
102		fprintf(stderr, "I:response rcode: %s\n",
103			isc_result_totext(result));
104			exit(-1);
105	}
106
107	result = dns_tkey_processdhresponse(query, response, ourkey, &nonce,
108					    &tsigkey, ring);
109	CHECK("dns_tkey_processdhresponse", result);
110
111	/*
112	 * Yes, this is a hack.
113	 */
114	isc_buffer_init(&keynamebuf, keyname, sizeof(keyname));
115	result = dst_key_buildfilename(tsigkey->key, 0, "", &keynamebuf);
116	CHECK("dst_key_buildfilename", result);
117	printf("%.*s\n", (int)isc_buffer_usedlength(&keynamebuf),
118	       (char *)isc_buffer_base(&keynamebuf));
119	type = DST_TYPE_PRIVATE | DST_TYPE_PUBLIC | DST_TYPE_KEY;
120	result = dst_key_tofile(tsigkey->key, type, "");
121	CHECK("dst_key_tofile", result);
122
123	dns_message_destroy(&query);
124	dns_message_destroy(&response);
125	dns_request_destroy(&reqev->request);
126	isc_event_free(&event);
127	isc_app_shutdown();
128	return;
129}
130
131static void
132sendquery(isc_task_t *task, isc_event_t *event) {
133	struct in_addr inaddr;
134	isc_sockaddr_t address;
135	isc_region_t r;
136	isc_result_t result;
137	dns_fixedname_t keyname;
138	dns_fixedname_t ownername;
139	isc_buffer_t namestr, keybuf;
140	unsigned char keydata[9];
141	dns_message_t *query;
142	dns_request_t *request;
143	static char keystr[] = "0123456789ab";
144
145	isc_event_free(&event);
146
147	result = ISC_R_FAILURE;
148	if (inet_pton(AF_INET, "10.53.0.1", &inaddr) != 1)
149		CHECK("inet_pton", result);
150	isc_sockaddr_fromin(&address, &inaddr, PORT);
151
152	dns_fixedname_init(&keyname);
153	isc_buffer_init(&namestr, "tkeytest.", 9);
154	isc_buffer_add(&namestr, 9);
155	result = dns_name_fromtext(dns_fixedname_name(&keyname), &namestr,
156				   NULL, 0, NULL);
157	CHECK("dns_name_fromtext", result);
158
159	dns_fixedname_init(&ownername);
160	isc_buffer_init(&namestr, ownername_str, strlen(ownername_str));
161	isc_buffer_add(&namestr, strlen(ownername_str));
162	result = dns_name_fromtext(dns_fixedname_name(&ownername), &namestr,
163				   NULL, 0, NULL);
164	CHECK("dns_name_fromtext", result);
165
166	isc_buffer_init(&keybuf, keydata, 9);
167	result = isc_base64_decodestring(keystr, &keybuf);
168	CHECK("isc_base64_decodestring", result);
169
170	isc_buffer_usedregion(&keybuf, &r);
171
172	initialkey = NULL;
173	result = dns_tsigkey_create(dns_fixedname_name(&keyname),
174				    DNS_TSIG_HMACMD5_NAME,
175				    isc_buffer_base(&keybuf),
176				    isc_buffer_usedlength(&keybuf),
177				    ISC_FALSE, NULL, 0, 0, mctx, ring,
178				    &initialkey);
179	CHECK("dns_tsigkey_create", result);
180
181	query = NULL;
182	result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &query);
183	CHECK("dns_message_create", result);
184
185	result = dns_tkey_builddhquery(query, ourkey,
186				       dns_fixedname_name(&ownername),
187				       DNS_TSIG_HMACMD5_NAME, &nonce, 3600);
188	CHECK("dns_tkey_builddhquery", result);
189
190	request = NULL;
191	result = dns_request_create(requestmgr, query, &address,
192				    0, initialkey, TIMEOUT, task,
193				    recvquery, query, &request);
194	CHECK("dns_request_create", result);
195}
196
197int
198main(int argc, char *argv[]) {
199	char *ourkeyname;
200	isc_taskmgr_t *taskmgr;
201	isc_timermgr_t *timermgr;
202	isc_socketmgr_t *socketmgr;
203	isc_socket_t *sock;
204	unsigned int attrs, attrmask;
205	isc_sockaddr_t bind_any;
206	dns_dispatchmgr_t *dispatchmgr;
207	dns_dispatch_t *dispatchv4;
208	dns_view_t *view;
209	isc_entropy_t *ectx;
210	dns_tkeyctx_t *tctx;
211	isc_log_t *log;
212	isc_logconfig_t *logconfig;
213	isc_task_t *task;
214	isc_result_t result;
215	int type;
216
217	RUNCHECK(isc_app_start());
218
219	if (argc < 2) {
220		fprintf(stderr, "I:no DH key provided\n");
221		exit(-1);
222	}
223	ourkeyname = argv[1];
224
225	if (argc >= 3)
226		ownername_str = argv[2];
227
228	dns_result_register();
229
230	mctx = NULL;
231	RUNCHECK(isc_mem_create(0, 0, &mctx));
232
233	ectx = NULL;
234	RUNCHECK(isc_entropy_create(mctx, &ectx));
235	RUNCHECK(isc_entropy_createfilesource(ectx, "random.data"));
236	RUNCHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE));
237
238	log = NULL;
239	logconfig = NULL;
240	RUNCHECK(isc_log_create(mctx, &log, &logconfig));
241
242	RUNCHECK(dst_lib_init(mctx, ectx, ISC_ENTROPY_GOODONLY));
243
244	taskmgr = NULL;
245	RUNCHECK(isc_taskmgr_create(mctx, 1, 0, &taskmgr));
246	task = NULL;
247	RUNCHECK(isc_task_create(taskmgr, 0, &task));
248	timermgr = NULL;
249	RUNCHECK(isc_timermgr_create(mctx, &timermgr));
250	socketmgr = NULL;
251	RUNCHECK(isc_socketmgr_create(mctx, &socketmgr));
252	dispatchmgr = NULL;
253	RUNCHECK(dns_dispatchmgr_create(mctx, NULL, &dispatchmgr));
254	isc_sockaddr_any(&bind_any);
255	attrs = DNS_DISPATCHATTR_UDP |
256		DNS_DISPATCHATTR_MAKEQUERY |
257		DNS_DISPATCHATTR_IPV4;
258	attrmask = DNS_DISPATCHATTR_UDP |
259		   DNS_DISPATCHATTR_TCP |
260		   DNS_DISPATCHATTR_IPV4 |
261		   DNS_DISPATCHATTR_IPV6;
262	dispatchv4 = NULL;
263	RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr,
264					  &bind_any, 4096, 4, 2, 3, 5,
265					  attrs, attrmask, &dispatchv4));
266	requestmgr = NULL;
267	RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr,
268					    dispatchmgr, dispatchv4, NULL,
269					    &requestmgr));
270
271	ring = NULL;
272	RUNCHECK(dns_tsigkeyring_create(mctx, &ring));
273	tctx = NULL;
274	RUNCHECK(dns_tkeyctx_create(mctx, ectx, &tctx));
275
276	view = NULL;
277	RUNCHECK(dns_view_create(mctx, 0, "_test", &view));
278	dns_view_setkeyring(view, ring);
279	dns_tsigkeyring_detach(&ring);
280
281	sock = NULL;
282	RUNCHECK(isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp,
283				   &sock));
284
285	RUNCHECK(isc_app_onrun(mctx, task, sendquery, NULL));
286
287	ourkey = NULL;
288	type = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_KEY;
289	result = dst_key_fromnamedfile(ourkeyname, NULL, type, mctx, &ourkey);
290	CHECK("dst_key_fromnamedfile", result);
291
292	isc_buffer_init(&nonce, noncedata, sizeof(noncedata));
293	result = isc_entropy_getdata(ectx, noncedata, sizeof(noncedata),
294				     NULL, ISC_ENTROPY_BLOCKING);
295	CHECK("isc_entropy_getdata", result);
296	isc_buffer_add(&nonce, sizeof(noncedata));
297
298	(void)isc_app_run();
299
300	dns_requestmgr_shutdown(requestmgr);
301	dns_requestmgr_detach(&requestmgr);
302	dns_dispatch_detach(&dispatchv4);
303	dns_dispatchmgr_destroy(&dispatchmgr);
304	isc_task_shutdown(task);
305	isc_task_detach(&task);
306	isc_taskmgr_destroy(&taskmgr);
307	isc_socket_detach(&sock);
308	isc_socketmgr_destroy(&socketmgr);
309	isc_timermgr_destroy(&timermgr);
310
311	dst_key_free(&ourkey);
312	dns_tsigkey_detach(&initialkey);
313	dns_tsigkey_detach(&tsigkey);
314
315	dns_tkeyctx_destroy(&tctx);
316
317	dns_view_detach(&view);
318
319	isc_log_destroy(&log);
320
321	dst_lib_destroy();
322	isc_hash_destroy();
323	isc_entropy_detach(&ectx);
324
325	isc_mem_destroy(&mctx);
326
327	isc_app_finish();
328
329	return (0);
330}
331