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