PageRenderTime 25ms CodeModel.GetById 2ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/bind9/lib/dns/gssapi_link.c

https://bitbucket.org/freebsd/freebsd-head/
C | 393 lines | 258 code | 59 blank | 76 comment | 53 complexity | 5086e8ccfbd7f74cf1a9e8d4e3530535 MD5 | raw file
  1/*
  2 * Copyright (C) 2004-2009, 2011, 2012  Internet Systems Consortium, Inc. ("ISC")
  3 * Copyright (C) 2000-2002  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/*
 19 * $Id$
 20 */
 21
 22#include <config.h>
 23
 24#ifdef GSSAPI
 25
 26#include <isc/base64.h>
 27#include <isc/buffer.h>
 28#include <isc/mem.h>
 29#include <isc/string.h>
 30#include <isc/util.h>
 31
 32#include <dst/result.h>
 33
 34#include "dst_internal.h"
 35#include "dst_parse.h"
 36
 37#include <dst/gssapi.h>
 38
 39#define INITIAL_BUFFER_SIZE 1024
 40#define BUFFER_EXTRA 1024
 41
 42#define REGION_TO_GBUFFER(r, gb) \
 43	do { \
 44		(gb).length = (r).length; \
 45		(gb).value = (r).base; \
 46	} while (0)
 47
 48#define GBUFFER_TO_REGION(gb, r) \
 49	do { \
 50		(r).length = (gb).length; \
 51		(r).base = (gb).value; \
 52	} while (0)
 53
 54
 55struct dst_gssapi_signverifyctx {
 56	isc_buffer_t *buffer;
 57};
 58
 59/*%
 60 * Allocate a temporary "context" for use in gathering data for signing
 61 * or verifying.
 62 */
 63static isc_result_t
 64gssapi_create_signverify_ctx(dst_key_t *key, dst_context_t *dctx) {
 65	dst_gssapi_signverifyctx_t *ctx;
 66	isc_result_t result;
 67
 68	UNUSED(key);
 69
 70	ctx = isc_mem_get(dctx->mctx, sizeof(dst_gssapi_signverifyctx_t));
 71	if (ctx == NULL)
 72		return (ISC_R_NOMEMORY);
 73	ctx->buffer = NULL;
 74	result = isc_buffer_allocate(dctx->mctx, &ctx->buffer,
 75				     INITIAL_BUFFER_SIZE);
 76	if (result != ISC_R_SUCCESS) {
 77		isc_mem_put(dctx->mctx, ctx, sizeof(dst_gssapi_signverifyctx_t));
 78		return (result);
 79	}
 80
 81	dctx->ctxdata.gssctx = ctx;
 82
 83	return (ISC_R_SUCCESS);
 84}
 85
 86/*%
 87 * Destroy the temporary sign/verify context.
 88 */
 89static void
 90gssapi_destroy_signverify_ctx(dst_context_t *dctx) {
 91	dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
 92
 93	if (ctx != NULL) {
 94		if (ctx->buffer != NULL)
 95			isc_buffer_free(&ctx->buffer);
 96		isc_mem_put(dctx->mctx, ctx, sizeof(dst_gssapi_signverifyctx_t));
 97		dctx->ctxdata.gssctx = NULL;
 98	}
 99}
100
101/*%
102 * Add data to our running buffer of data we will be signing or verifying.
103 * This code will see if the new data will fit in our existing buffer, and
104 * copy it in if it will.  If not, it will attempt to allocate a larger
105 * buffer and copy old+new into it, and free the old buffer.
106 */
107static isc_result_t
108gssapi_adddata(dst_context_t *dctx, const isc_region_t *data) {
109	dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
110	isc_buffer_t *newbuffer = NULL;
111	isc_region_t r;
112	unsigned int length;
113	isc_result_t result;
114
115	result = isc_buffer_copyregion(ctx->buffer, data);
116	if (result == ISC_R_SUCCESS)
117		return (ISC_R_SUCCESS);
118
119	length = isc_buffer_length(ctx->buffer) + data->length + BUFFER_EXTRA;
120
121	result = isc_buffer_allocate(dctx->mctx, &newbuffer, length);
122	if (result != ISC_R_SUCCESS)
123		return (result);
124
125	isc_buffer_usedregion(ctx->buffer, &r);
126	(void)isc_buffer_copyregion(newbuffer, &r);
127	(void)isc_buffer_copyregion(newbuffer, data);
128
129	isc_buffer_free(&ctx->buffer);
130	ctx->buffer = newbuffer;
131
132	return (ISC_R_SUCCESS);
133}
134
135/*%
136 * Sign.
137 */
138static isc_result_t
139gssapi_sign(dst_context_t *dctx, isc_buffer_t *sig) {
140	dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
141	isc_region_t message;
142	gss_buffer_desc gmessage, gsig;
143	OM_uint32 minor, gret;
144	gss_ctx_id_t gssctx = dctx->key->keydata.gssctx;
145	char buf[1024];
146
147	/*
148	 * Convert the data we wish to sign into a structure gssapi can
149	 * understand.
150	 */
151	isc_buffer_usedregion(ctx->buffer, &message);
152	REGION_TO_GBUFFER(message, gmessage);
153
154	/*
155	 * Generate the signature.
156	 */
157	gret = gss_get_mic(&minor, gssctx, GSS_C_QOP_DEFAULT, &gmessage,
158			   &gsig);
159
160	/*
161	 * If it did not complete, we log the result and return a generic
162	 * failure code.
163	 */
164	if (gret != GSS_S_COMPLETE) {
165		gss_log(3, "GSS sign error: %s",
166			gss_error_tostring(gret, minor, buf, sizeof(buf)));
167		return (ISC_R_FAILURE);
168	}
169
170	/*
171	 * If it will not fit in our allocated buffer, return that we need
172	 * more space.
173	 */
174	if (gsig.length > isc_buffer_availablelength(sig)) {
175		gss_release_buffer(&minor, &gsig);
176		return (ISC_R_NOSPACE);
177	}
178
179	/*
180	 * Copy the output into our buffer space, and release the gssapi
181	 * allocated space.
182	 */
183	isc_buffer_putmem(sig, gsig.value, gsig.length);
184	if (gsig.length != 0U)
185		gss_release_buffer(&minor, &gsig);
186
187	return (ISC_R_SUCCESS);
188}
189
190/*%
191 * Verify.
192 */
193static isc_result_t
194gssapi_verify(dst_context_t *dctx, const isc_region_t *sig) {
195	dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
196	isc_region_t message, r;
197	gss_buffer_desc gmessage, gsig;
198	OM_uint32 minor, gret;
199	gss_ctx_id_t gssctx = dctx->key->keydata.gssctx;
200	unsigned char *buf;
201	char err[1024];
202
203	/*
204	 * Convert the data we wish to sign into a structure gssapi can
205	 * understand.
206	 */
207	isc_buffer_usedregion(ctx->buffer, &message);
208	REGION_TO_GBUFFER(message, gmessage);
209
210	/*
211	 * XXXMLG
212	 * It seem that gss_verify_mic() modifies the signature buffer,
213	 * at least on Heimdal's implementation.  Copy it here to an allocated
214	 * buffer.
215	 */
216	buf = isc_mem_allocate(dst__memory_pool, sig->length);
217	if (buf == NULL)
218		return (ISC_R_FAILURE);
219	memcpy(buf, sig->base, sig->length);
220	r.base = buf;
221	r.length = sig->length;
222	REGION_TO_GBUFFER(r, gsig);
223
224	/*
225	 * Verify the data.
226	 */
227	gret = gss_verify_mic(&minor, gssctx, &gmessage, &gsig, NULL);
228
229	isc_mem_free(dst__memory_pool, buf);
230
231	/*
232	 * Convert return codes into something useful to us.
233	 */
234	if (gret != GSS_S_COMPLETE) {
235		gss_log(3, "GSS verify error: %s",
236			gss_error_tostring(gret, minor, err, sizeof(err)));
237		if (gret == GSS_S_DEFECTIVE_TOKEN ||
238		    gret == GSS_S_BAD_SIG ||
239		    gret == GSS_S_DUPLICATE_TOKEN ||
240		    gret == GSS_S_OLD_TOKEN ||
241		    gret == GSS_S_UNSEQ_TOKEN ||
242		    gret == GSS_S_GAP_TOKEN ||
243		    gret == GSS_S_CONTEXT_EXPIRED ||
244		    gret == GSS_S_NO_CONTEXT ||
245		    gret == GSS_S_FAILURE)
246			return(DST_R_VERIFYFAILURE);
247		else
248			return (ISC_R_FAILURE);
249	}
250
251	return (ISC_R_SUCCESS);
252}
253
254static isc_boolean_t
255gssapi_compare(const dst_key_t *key1, const dst_key_t *key2) {
256	gss_ctx_id_t gsskey1 = key1->keydata.gssctx;
257	gss_ctx_id_t gsskey2 = key2->keydata.gssctx;
258
259	/* No idea */
260	return (ISC_TF(gsskey1 == gsskey2));
261}
262
263static isc_result_t
264gssapi_generate(dst_key_t *key, int unused, void (*callback)(int)) {
265	UNUSED(key);
266	UNUSED(unused);
267	UNUSED(callback);
268
269	/* No idea */
270	return (ISC_R_FAILURE);
271}
272
273static isc_boolean_t
274gssapi_isprivate(const dst_key_t *key) {
275	UNUSED(key);
276	return (ISC_TRUE);
277}
278
279static void
280gssapi_destroy(dst_key_t *key) {
281	REQUIRE(key != NULL);
282	dst_gssapi_deletectx(key->mctx, &key->keydata.gssctx);
283	key->keydata.gssctx = NULL;
284}
285
286static isc_result_t
287gssapi_restore(dst_key_t *key, const char *keystr) {
288	OM_uint32 major, minor;
289	size_t len;
290	isc_buffer_t *b = NULL;
291	isc_region_t r;
292	gss_buffer_desc gssbuffer;
293	isc_result_t result;
294
295	len = strlen(keystr);
296	if ((len % 4) != 0U)
297		return (ISC_R_BADBASE64);
298
299	len = (len / 4) * 3;
300
301	result = isc_buffer_allocate(key->mctx, &b, len);
302	if (result != ISC_R_SUCCESS)
303		return (result);
304
305	result = isc_base64_decodestring(keystr, b);
306	if (result != ISC_R_SUCCESS) {
307		isc_buffer_free(&b);
308		return (result);
309	}
310
311	isc_buffer_remainingregion(b, &r);
312	REGION_TO_GBUFFER(r, gssbuffer);
313	major = gss_import_sec_context(&minor, &gssbuffer,
314				       &key->keydata.gssctx);
315	if (major != GSS_S_COMPLETE) {
316		isc_buffer_free(&b);
317		return (ISC_R_FAILURE);
318	}
319
320	isc_buffer_free(&b);
321	return (ISC_R_SUCCESS);
322}
323
324static isc_result_t
325gssapi_dump(dst_key_t *key, isc_mem_t *mctx, char **buffer, int *length) {
326	OM_uint32 major, minor;
327	gss_buffer_desc gssbuffer;
328	size_t len;
329	char *buf;
330	isc_buffer_t b;
331	isc_region_t r;
332	isc_result_t result;
333
334	major = gss_export_sec_context(&minor, &key->keydata.gssctx,
335				       &gssbuffer);
336	if (major != GSS_S_COMPLETE) {
337		fprintf(stderr, "gss_export_sec_context -> %d, %d\n",
338			major, minor);
339		return (ISC_R_FAILURE);
340	}
341	if (gssbuffer.length == 0U)
342		return (ISC_R_FAILURE);
343	len = ((gssbuffer.length + 2)/3) * 4;
344	buf = isc_mem_get(mctx, len);
345	if (buf == NULL) {
346		gss_release_buffer(&minor, &gssbuffer);
347		return (ISC_R_NOMEMORY);
348	}
349	isc_buffer_init(&b, buf, len);
350	GBUFFER_TO_REGION(gssbuffer, r);
351	result = isc_base64_totext(&r, 0, "", &b);
352	RUNTIME_CHECK(result == ISC_R_SUCCESS);
353	gss_release_buffer(&minor, &gssbuffer);
354	*buffer = buf;
355	*length = len;
356	return (ISC_R_SUCCESS);
357}
358
359static dst_func_t gssapi_functions = {
360	gssapi_create_signverify_ctx,
361	gssapi_destroy_signverify_ctx,
362	gssapi_adddata,
363	gssapi_sign,
364	gssapi_verify,
365	NULL, /*%< computesecret */
366	gssapi_compare,
367	NULL, /*%< paramcompare */
368	gssapi_generate,
369	gssapi_isprivate,
370	gssapi_destroy,
371	NULL, /*%< todns */
372	NULL, /*%< fromdns */
373	NULL, /*%< tofile */
374	NULL, /*%< parse */
375	NULL, /*%< cleanup */
376	NULL,  /*%< fromlabel */
377	gssapi_dump,
378	gssapi_restore,
379};
380
381isc_result_t
382dst__gssapi_init(dst_func_t **funcp) {
383	REQUIRE(funcp != NULL);
384	if (*funcp == NULL)
385		*funcp = &gssapi_functions;
386	return (ISC_R_SUCCESS);
387}
388
389#else
390int  gssapi_link_unneeded = 1;
391#endif
392
393/*! \file */