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