1135446Strhodes/*
2254402Serwin * Copyright (C) 2004-2007, 2009, 2011, 2012  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 1999-2001  Internet Software Consortium.
4135446Strhodes *
5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18234010Sdougb/* $Id: tsigconf.c,v 1.35 2011/01/11 23:47:12 tbox Exp $ */
19135446Strhodes
20170222Sdougb/*! \file */
21170222Sdougb
22135446Strhodes#include <config.h>
23135446Strhodes
24135446Strhodes#include <isc/base64.h>
25135446Strhodes#include <isc/buffer.h>
26135446Strhodes#include <isc/mem.h>
27135446Strhodes#include <isc/string.h>
28135446Strhodes
29135446Strhodes#include <isccfg/cfg.h>
30135446Strhodes
31135446Strhodes#include <dns/tsig.h>
32135446Strhodes#include <dns/result.h>
33135446Strhodes
34135446Strhodes#include <named/log.h>
35135446Strhodes
36135446Strhodes#include <named/config.h>
37135446Strhodes#include <named/tsigconf.h>
38135446Strhodes
39135446Strhodesstatic isc_result_t
40165071Sdougbadd_initial_keys(const cfg_obj_t *list, dns_tsig_keyring_t *ring,
41165071Sdougb		 isc_mem_t *mctx)
42165071Sdougb{
43170222Sdougb	dns_tsigkey_t *tsigkey = NULL;
44165071Sdougb	const cfg_listelt_t *element;
45165071Sdougb	const cfg_obj_t *key = NULL;
46165071Sdougb	const char *keyid = NULL;
47135446Strhodes	unsigned char *secret = NULL;
48135446Strhodes	int secretalloc = 0;
49135446Strhodes	int secretlen = 0;
50135446Strhodes	isc_result_t ret;
51135446Strhodes	isc_stdtime_t now;
52170222Sdougb	isc_uint16_t bits;
53135446Strhodes
54135446Strhodes	for (element = cfg_list_first(list);
55135446Strhodes	     element != NULL;
56135446Strhodes	     element = cfg_list_next(element))
57135446Strhodes	{
58165071Sdougb		const cfg_obj_t *algobj = NULL;
59165071Sdougb		const cfg_obj_t *secretobj = NULL;
60135446Strhodes		dns_name_t keyname;
61135446Strhodes		dns_name_t *alg;
62165071Sdougb		const char *algstr;
63135446Strhodes		char keynamedata[1024];
64135446Strhodes		isc_buffer_t keynamesrc, keynamebuf;
65165071Sdougb		const char *secretstr;
66135446Strhodes		isc_buffer_t secretbuf;
67135446Strhodes
68135446Strhodes		key = cfg_listelt_value(element);
69135446Strhodes		keyid = cfg_obj_asstring(cfg_map_getname(key));
70135446Strhodes
71135446Strhodes		algobj = NULL;
72135446Strhodes		secretobj = NULL;
73135446Strhodes		(void)cfg_map_get(key, "algorithm", &algobj);
74135446Strhodes		(void)cfg_map_get(key, "secret", &secretobj);
75135446Strhodes		INSIST(algobj != NULL && secretobj != NULL);
76135446Strhodes
77135446Strhodes		/*
78135446Strhodes		 * Create the key name.
79135446Strhodes		 */
80135446Strhodes		dns_name_init(&keyname, NULL);
81254402Serwin		isc_buffer_constinit(&keynamesrc, keyid, strlen(keyid));
82135446Strhodes		isc_buffer_add(&keynamesrc, strlen(keyid));
83135446Strhodes		isc_buffer_init(&keynamebuf, keynamedata, sizeof(keynamedata));
84135446Strhodes		ret = dns_name_fromtext(&keyname, &keynamesrc, dns_rootname,
85224092Sdougb					DNS_NAME_DOWNCASE, &keynamebuf);
86135446Strhodes		if (ret != ISC_R_SUCCESS)
87135446Strhodes			goto failure;
88135446Strhodes
89135446Strhodes		/*
90135446Strhodes		 * Create the algorithm.
91135446Strhodes		 */
92135446Strhodes		algstr = cfg_obj_asstring(algobj);
93170222Sdougb		if (ns_config_getkeyalgorithm(algstr, &alg, &bits)
94170222Sdougb		    != ISC_R_SUCCESS) {
95135446Strhodes			cfg_obj_log(algobj, ns_g_lctx, ISC_LOG_ERROR,
96170222Sdougb				    "key '%s': has a unsupported algorithm '%s'",
97170222Sdougb				    keyid, algstr);
98135446Strhodes			ret = DNS_R_BADALG;
99135446Strhodes			goto failure;
100135446Strhodes		}
101135446Strhodes
102135446Strhodes		secretstr = cfg_obj_asstring(secretobj);
103135446Strhodes		secretalloc = secretlen = strlen(secretstr) * 3 / 4;
104135446Strhodes		secret = isc_mem_get(mctx, secretlen);
105135446Strhodes		if (secret == NULL) {
106135446Strhodes			ret = ISC_R_NOMEMORY;
107135446Strhodes			goto failure;
108135446Strhodes		}
109135446Strhodes		isc_buffer_init(&secretbuf, secret, secretlen);
110135446Strhodes		ret = isc_base64_decodestring(secretstr, &secretbuf);
111135446Strhodes		if (ret != ISC_R_SUCCESS)
112135446Strhodes			goto failure;
113135446Strhodes		secretlen = isc_buffer_usedlength(&secretbuf);
114135446Strhodes
115135446Strhodes		isc_stdtime_get(&now);
116135446Strhodes		ret = dns_tsigkey_create(&keyname, alg, secret, secretlen,
117135446Strhodes					 ISC_FALSE, NULL, now, now,
118170222Sdougb					 mctx, ring, &tsigkey);
119135446Strhodes		isc_mem_put(mctx, secret, secretalloc);
120135446Strhodes		secret = NULL;
121135446Strhodes		if (ret != ISC_R_SUCCESS)
122135446Strhodes			goto failure;
123170222Sdougb		/*
124170222Sdougb		 * Set digest bits.
125170222Sdougb		 */
126170222Sdougb		dst_key_setbits(tsigkey->key, bits);
127170222Sdougb		dns_tsigkey_detach(&tsigkey);
128135446Strhodes	}
129135446Strhodes
130135446Strhodes	return (ISC_R_SUCCESS);
131135446Strhodes
132135446Strhodes failure:
133135446Strhodes	cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
134135446Strhodes		    "configuring key '%s': %s", keyid,
135135446Strhodes		    isc_result_totext(ret));
136135446Strhodes
137135446Strhodes	if (secret != NULL)
138135446Strhodes		isc_mem_put(mctx, secret, secretalloc);
139135446Strhodes	return (ret);
140135446Strhodes}
141135446Strhodes
142135446Strhodesisc_result_t
143165071Sdougbns_tsigkeyring_fromconfig(const cfg_obj_t *config, const cfg_obj_t *vconfig,
144135446Strhodes			  isc_mem_t *mctx, dns_tsig_keyring_t **ringp)
145135446Strhodes{
146165071Sdougb	const cfg_obj_t *maps[3];
147165071Sdougb	const cfg_obj_t *keylist;
148135446Strhodes	dns_tsig_keyring_t *ring = NULL;
149135446Strhodes	isc_result_t result;
150135446Strhodes	int i;
151135446Strhodes
152224092Sdougb	REQUIRE(ringp != NULL && *ringp == NULL);
153224092Sdougb
154135446Strhodes	i = 0;
155135446Strhodes	if (config != NULL)
156135446Strhodes		maps[i++] = config;
157135446Strhodes	if (vconfig != NULL)
158135446Strhodes		maps[i++] = cfg_tuple_get(vconfig, "options");
159135446Strhodes	maps[i] = NULL;
160135446Strhodes
161135446Strhodes	result = dns_tsigkeyring_create(mctx, &ring);
162135446Strhodes	if (result != ISC_R_SUCCESS)
163135446Strhodes		return (result);
164135446Strhodes
165135446Strhodes	for (i = 0; ; i++) {
166135446Strhodes		if (maps[i] == NULL)
167135446Strhodes			break;
168135446Strhodes		keylist = NULL;
169135446Strhodes		result = cfg_map_get(maps[i], "key", &keylist);
170135446Strhodes		if (result != ISC_R_SUCCESS)
171135446Strhodes			continue;
172135446Strhodes		result = add_initial_keys(keylist, ring, mctx);
173135446Strhodes		if (result != ISC_R_SUCCESS)
174135446Strhodes			goto failure;
175135446Strhodes	}
176135446Strhodes
177135446Strhodes	*ringp = ring;
178135446Strhodes	return (ISC_R_SUCCESS);
179135446Strhodes
180135446Strhodes failure:
181224092Sdougb	dns_tsigkeyring_detach(&ring);
182135446Strhodes	return (result);
183135446Strhodes}
184