[BACK]Return to gssapi_link.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / external / mpl / bind / dist / lib / dns

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>