"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.16.7/lib/dns/gssapi_link.c" (4 Sep 2020, 8598 Bytes) of package /linux/misc/dns/bind9/9.16.7/bind-9.16.7.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "gssapi_link.c" see the Fossies "Dox" file reference documentation.

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