Import bind 9.5.2 vendor sources.
[dragonfly.git] / contrib / bind-9.5.2 / lib / dns / gssapi_link.c
1 /*
2  * Copyright (C) 2004-2008  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.7.128.5 2008/07/23 10:33:26 marka Exp $
20  */
21
22 #include <config.h>
23
24 #ifdef GSSAPI
25
26 #include <isc/buffer.h>
27 #include <isc/mem.h>
28 #include <isc/string.h>
29 #include <isc/util.h>
30
31 #include <dst/result.h>
32
33 #include "dst_internal.h"
34 #include "dst_parse.h"
35
36 #include <dst/gssapi.h>
37
38 #define INITIAL_BUFFER_SIZE 1024
39 #define BUFFER_EXTRA 1024
40
41 #define REGION_TO_GBUFFER(r, gb) \
42         do { \
43                 (gb).length = (r).length; \
44                 (gb).value = (r).base; \
45         } while (0)
46
47
48 struct dst_gssapi_signverifyctx {
49         isc_buffer_t *buffer;
50 };
51
52 /*%
53  * Allocate a temporary "context" for use in gathering data for signing
54  * or verifying.
55  */
56 static isc_result_t
57 gssapi_create_signverify_ctx(dst_key_t *key, dst_context_t *dctx) {
58         dst_gssapi_signverifyctx_t *ctx;
59         isc_result_t result;
60
61         UNUSED(key);
62
63         ctx = isc_mem_get(dctx->mctx, sizeof(dst_gssapi_signverifyctx_t));
64         if (ctx == NULL)
65                 return (ISC_R_NOMEMORY);
66         ctx->buffer = NULL;
67         result = isc_buffer_allocate(dctx->mctx, &ctx->buffer,
68                                      INITIAL_BUFFER_SIZE);
69         if (result != ISC_R_SUCCESS) {
70                 isc_mem_put(dctx->mctx, ctx, sizeof(dst_gssapi_signverifyctx_t));
71                 return (result);
72         }
73
74         dctx->ctxdata.gssctx = ctx;
75
76         return (ISC_R_SUCCESS);
77 }
78
79 /*%
80  * Destroy the temporary sign/verify context.
81  */
82 static void
83 gssapi_destroy_signverify_ctx(dst_context_t *dctx) {
84         dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
85
86         if (ctx != NULL) {
87                 if (ctx->buffer != NULL)
88                         isc_buffer_free(&ctx->buffer);
89                 isc_mem_put(dctx->mctx, ctx, sizeof(dst_gssapi_signverifyctx_t));
90                 dctx->ctxdata.gssctx = NULL;
91         }
92 }
93
94 /*%
95  * Add data to our running buffer of data we will be signing or verifying.
96  * This code will see if the new data will fit in our existing buffer, and
97  * copy it in if it will.  If not, it will attempt to allocate a larger
98  * buffer and copy old+new into it, and free the old buffer.
99  */
100 static isc_result_t
101 gssapi_adddata(dst_context_t *dctx, const isc_region_t *data) {
102         dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
103         isc_buffer_t *newbuffer = NULL;
104         isc_region_t r;
105         unsigned int length;
106         isc_result_t result;
107
108         result = isc_buffer_copyregion(ctx->buffer, data);
109         if (result == ISC_R_SUCCESS)
110                 return (ISC_R_SUCCESS);
111
112         length = isc_buffer_length(ctx->buffer) + data->length + BUFFER_EXTRA;
113
114         result = isc_buffer_allocate(dctx->mctx, &newbuffer, length);
115         if (result != ISC_R_SUCCESS)
116                 return (result);
117
118         isc_buffer_usedregion(ctx->buffer, &r);
119         (void)isc_buffer_copyregion(newbuffer, &r);
120         (void)isc_buffer_copyregion(newbuffer, data);
121
122         isc_buffer_free(&ctx->buffer);
123         ctx->buffer = newbuffer;
124
125         return (ISC_R_SUCCESS);
126 }
127
128 /*%
129  * Sign.
130  */
131 static isc_result_t
132 gssapi_sign(dst_context_t *dctx, isc_buffer_t *sig) {
133         dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
134         isc_region_t message;
135         gss_buffer_desc gmessage, gsig;
136         OM_uint32 minor, gret;
137         gss_ctx_id_t gssctx = dctx->key->keydata.gssctx;
138         char buf[1024];
139
140         /*
141          * Convert the data we wish to sign into a structure gssapi can
142          * understand.
143          */
144         isc_buffer_usedregion(ctx->buffer, &message);
145         REGION_TO_GBUFFER(message, gmessage);
146
147         /*
148          * Generate the signature.
149          */
150         gret = gss_get_mic(&minor, gssctx, GSS_C_QOP_DEFAULT, &gmessage,
151                            &gsig);
152
153         /*
154          * If it did not complete, we log the result and return a generic
155          * failure code.
156          */
157         if (gret != GSS_S_COMPLETE) {
158                 gss_log(3, "GSS sign error: %s",
159                         gss_error_tostring(gret, minor, buf, sizeof(buf)));
160                 return (ISC_R_FAILURE);
161         }
162
163         /*
164          * If it will not fit in our allocated buffer, return that we need
165          * more space.
166          */
167         if (gsig.length > isc_buffer_availablelength(sig)) {
168                 gss_release_buffer(&minor, &gsig);
169                 return (ISC_R_NOSPACE);
170         }
171
172         /*
173          * Copy the output into our buffer space, and release the gssapi
174          * allocated space.
175          */
176         isc_buffer_putmem(sig, gsig.value, gsig.length);
177         if (gsig.length != 0)
178                 gss_release_buffer(&minor, &gsig);
179
180         return (ISC_R_SUCCESS);
181 }
182
183 /*%
184  * Verify.
185  */
186 static isc_result_t
187 gssapi_verify(dst_context_t *dctx, const isc_region_t *sig) {
188         dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
189         isc_region_t message, r;
190         gss_buffer_desc gmessage, gsig;
191         OM_uint32 minor, gret;
192         gss_ctx_id_t gssctx = dctx->key->keydata.gssctx;
193         unsigned char *buf;
194         char err[1024];
195
196         /*
197          * Convert the data we wish to sign into a structure gssapi can
198          * understand.
199          */
200         isc_buffer_usedregion(ctx->buffer, &message);
201         REGION_TO_GBUFFER(message, gmessage);
202
203         /*
204          * XXXMLG
205          * It seem that gss_verify_mic() modifies the signature buffer,
206          * at least on Heimdal's implementation.  Copy it here to an allocated
207          * buffer.
208          */
209         buf = isc_mem_allocate(dst__memory_pool, sig->length);
210         if (buf == NULL)
211                 return (ISC_R_FAILURE);
212         memcpy(buf, sig->base, sig->length);
213         r.base = buf;
214         r.length = sig->length;
215         REGION_TO_GBUFFER(r, gsig);
216
217         /*
218          * Verify the data.
219          */
220         gret = gss_verify_mic(&minor, gssctx, &gmessage, &gsig, NULL);
221
222         isc_mem_free(dst__memory_pool, buf);
223
224         /*
225          * Convert return codes into something useful to us.
226          */
227         if (gret != GSS_S_COMPLETE) {
228                 gss_log(3, "GSS verify error: %s",
229                         gss_error_tostring(gret, minor, err, sizeof(err)));
230                 if (gret == GSS_S_DEFECTIVE_TOKEN ||
231                     gret == GSS_S_BAD_SIG ||
232                     gret == GSS_S_DUPLICATE_TOKEN ||
233                     gret == GSS_S_OLD_TOKEN ||
234                     gret == GSS_S_UNSEQ_TOKEN ||
235                     gret == GSS_S_GAP_TOKEN ||
236                     gret == GSS_S_CONTEXT_EXPIRED ||
237                     gret == GSS_S_NO_CONTEXT ||
238                     gret == GSS_S_FAILURE)
239                         return(DST_R_VERIFYFAILURE);
240                 else
241                         return (ISC_R_FAILURE);
242         }
243
244         return (ISC_R_SUCCESS);
245 }
246
247 static isc_boolean_t
248 gssapi_compare(const dst_key_t *key1, const dst_key_t *key2) {
249         gss_ctx_id_t gsskey1 = key1->keydata.gssctx;
250         gss_ctx_id_t gsskey2 = key2->keydata.gssctx;
251
252         /* No idea */
253         return (ISC_TF(gsskey1 == gsskey2));
254 }
255
256 static isc_result_t
257 gssapi_generate(dst_key_t *key, int unused) {
258         UNUSED(key);
259         UNUSED(unused);
260
261         /* No idea */
262         return (ISC_R_FAILURE);
263 }
264
265 static isc_boolean_t
266 gssapi_isprivate(const dst_key_t *key) {
267         UNUSED(key);
268         return (ISC_TRUE);
269 }
270
271 static void
272 gssapi_destroy(dst_key_t *key) {
273         REQUIRE(key != NULL);
274         dst_gssapi_deletectx(key->mctx, &key->keydata.gssctx);
275         key->keydata.gssctx = NULL;
276 }
277
278 static dst_func_t gssapi_functions = {
279         gssapi_create_signverify_ctx,
280         gssapi_destroy_signverify_ctx,
281         gssapi_adddata,
282         gssapi_sign,
283         gssapi_verify,
284         NULL, /*%< computesecret */
285         gssapi_compare,
286         NULL, /*%< paramcompare */
287         gssapi_generate,
288         gssapi_isprivate,
289         gssapi_destroy,
290         NULL, /*%< todns */
291         NULL, /*%< fromdns */
292         NULL, /*%< tofile */
293         NULL, /*%< parse */
294         NULL /*%< cleanup */
295 };
296
297 isc_result_t
298 dst__gssapi_init(dst_func_t **funcp) {
299         REQUIRE(funcp != NULL);
300         if (*funcp == NULL)
301                 *funcp = &gssapi_functions;
302         return (ISC_R_SUCCESS);
303 }
304
305 #else
306 int  gssapi_link_unneeded = 1;
307 #endif
308
309 /*! \file */