gssapi_link.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2009, 2011-2014  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 2000-2002  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /*
00019  * $Id: gssapi_link.c,v 1.17 2011/03/28 05:32:16 marka Exp $
00020  */
00021 
00022 #include <config.h>
00023 
00024 #ifdef GSSAPI
00025 
00026 #include <isc/base64.h>
00027 #include <isc/buffer.h>
00028 #include <isc/mem.h>
00029 #include <isc/string.h>
00030 #include <isc/util.h>
00031 
00032 #include <dst/result.h>
00033 
00034 #include "dst_internal.h"
00035 #include "dst_parse.h"
00036 
00037 #include <dst/gssapi.h>
00038 
00039 #define INITIAL_BUFFER_SIZE 1024
00040 #define BUFFER_EXTRA 1024
00041 
00042 #define REGION_TO_GBUFFER(r, gb) \
00043         do { \
00044                 (gb).length = (r).length; \
00045                 (gb).value = (r).base; \
00046         } while (0)
00047 
00048 #define GBUFFER_TO_REGION(gb, r) \
00049         do { \
00050           (r).length = (unsigned int)(gb).length; \
00051                 (r).base = (gb).value; \
00052         } while (0)
00053 
00054 
00055 struct dst_gssapi_signverifyctx {
00056         isc_buffer_t *buffer;
00057 };
00058 
00059 /*%
00060  * Allocate a temporary "context" for use in gathering data for signing
00061  * or verifying.
00062  */
00063 static isc_result_t
00064 gssapi_create_signverify_ctx(dst_key_t *key, dst_context_t *dctx) {
00065         dst_gssapi_signverifyctx_t *ctx;
00066         isc_result_t result;
00067 
00068         UNUSED(key);
00069 
00070         ctx = isc_mem_get(dctx->mctx, sizeof(dst_gssapi_signverifyctx_t));
00071         if (ctx == NULL)
00072                 return (ISC_R_NOMEMORY);
00073         ctx->buffer = NULL;
00074         result = isc_buffer_allocate(dctx->mctx, &ctx->buffer,
00075                                      INITIAL_BUFFER_SIZE);
00076         if (result != ISC_R_SUCCESS) {
00077                 isc_mem_put(dctx->mctx, ctx, sizeof(dst_gssapi_signverifyctx_t));
00078                 return (result);
00079         }
00080 
00081         dctx->ctxdata.gssctx = ctx;
00082 
00083         return (ISC_R_SUCCESS);
00084 }
00085 
00086 /*%
00087  * Destroy the temporary sign/verify context.
00088  */
00089 static void
00090 gssapi_destroy_signverify_ctx(dst_context_t *dctx) {
00091         dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
00092 
00093         if (ctx != NULL) {
00094                 if (ctx->buffer != NULL)
00095                         isc_buffer_free(&ctx->buffer);
00096                 isc_mem_put(dctx->mctx, ctx, sizeof(dst_gssapi_signverifyctx_t));
00097                 dctx->ctxdata.gssctx = NULL;
00098         }
00099 }
00100 
00101 /*%
00102  * Add data to our running buffer of data we will be signing or verifying.
00103  * This code will see if the new data will fit in our existing buffer, and
00104  * copy it in if it will.  If not, it will attempt to allocate a larger
00105  * buffer and copy old+new into it, and free the old buffer.
00106  */
00107 static isc_result_t
00108 gssapi_adddata(dst_context_t *dctx, const isc_region_t *data) {
00109         dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
00110         isc_buffer_t *newbuffer = NULL;
00111         isc_region_t r;
00112         unsigned int length;
00113         isc_result_t result;
00114 
00115         result = isc_buffer_copyregion(ctx->buffer, data);
00116         if (result == ISC_R_SUCCESS)
00117                 return (ISC_R_SUCCESS);
00118 
00119         length = isc_buffer_length(ctx->buffer) + data->length + BUFFER_EXTRA;
00120 
00121         result = isc_buffer_allocate(dctx->mctx, &newbuffer, length);
00122         if (result != ISC_R_SUCCESS)
00123                 return (result);
00124 
00125         isc_buffer_usedregion(ctx->buffer, &r);
00126         (void)isc_buffer_copyregion(newbuffer, &r);
00127         (void)isc_buffer_copyregion(newbuffer, data);
00128 
00129         isc_buffer_free(&ctx->buffer);
00130         ctx->buffer = newbuffer;
00131 
00132         return (ISC_R_SUCCESS);
00133 }
00134 
00135 /*%
00136  * Sign.
00137  */
00138 static isc_result_t
00139 gssapi_sign(dst_context_t *dctx, isc_buffer_t *sig) {
00140         dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
00141         isc_region_t message;
00142         gss_buffer_desc gmessage, gsig;
00143         OM_uint32 minor, gret;
00144         gss_ctx_id_t gssctx = dctx->key->keydata.gssctx;
00145         char buf[1024];
00146 
00147         /*
00148          * Convert the data we wish to sign into a structure gssapi can
00149          * understand.
00150          */
00151         isc_buffer_usedregion(ctx->buffer, &message);
00152         REGION_TO_GBUFFER(message, gmessage);
00153 
00154         /*
00155          * Generate the signature.
00156          */
00157         gret = gss_get_mic(&minor, gssctx, GSS_C_QOP_DEFAULT, &gmessage,
00158                            &gsig);
00159 
00160         /*
00161          * If it did not complete, we log the result and return a generic
00162          * failure code.
00163          */
00164         if (gret != GSS_S_COMPLETE) {
00165                 gss_log(3, "GSS sign error: %s",
00166                         gss_error_tostring(gret, minor, buf, sizeof(buf)));
00167                 return (ISC_R_FAILURE);
00168         }
00169 
00170         /*
00171          * If it will not fit in our allocated buffer, return that we need
00172          * more space.
00173          */
00174         if (gsig.length > isc_buffer_availablelength(sig)) {
00175                 gss_release_buffer(&minor, &gsig);
00176                 return (ISC_R_NOSPACE);
00177         }
00178 
00179         /*
00180          * Copy the output into our buffer space, and release the gssapi
00181          * allocated space.
00182          */
00183         isc_buffer_putmem(sig, gsig.value, (unsigned int)gsig.length);
00184         if (gsig.length != 0U)
00185                 gss_release_buffer(&minor, &gsig);
00186 
00187         return (ISC_R_SUCCESS);
00188 }
00189 
00190 /*%
00191  * Verify.
00192  */
00193 static isc_result_t
00194 gssapi_verify(dst_context_t *dctx, const isc_region_t *sig) {
00195         dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
00196         isc_region_t message, r;
00197         gss_buffer_desc gmessage, gsig;
00198         OM_uint32 minor, gret;
00199         gss_ctx_id_t gssctx = dctx->key->keydata.gssctx;
00200         unsigned char *buf;
00201         char err[1024];
00202 
00203         /*
00204          * Convert the data we wish to sign into a structure gssapi can
00205          * understand.
00206          */
00207         isc_buffer_usedregion(ctx->buffer, &message);
00208         REGION_TO_GBUFFER(message, gmessage);
00209 
00210         /*
00211          * XXXMLG
00212          * It seem that gss_verify_mic() modifies the signature buffer,
00213          * at least on Heimdal's implementation.  Copy it here to an allocated
00214          * buffer.
00215          */
00216         buf = isc_mem_allocate(dst__memory_pool, sig->length);
00217         if (buf == NULL)
00218                 return (ISC_R_FAILURE);
00219         memmove(buf, sig->base, sig->length);
00220         r.base = buf;
00221         r.length = sig->length;
00222         REGION_TO_GBUFFER(r, gsig);
00223 
00224         /*
00225          * Verify the data.
00226          */
00227         gret = gss_verify_mic(&minor, gssctx, &gmessage, &gsig, NULL);
00228 
00229         isc_mem_free(dst__memory_pool, buf);
00230 
00231         /*
00232          * Convert return codes into something useful to us.
00233          */
00234         if (gret != GSS_S_COMPLETE) {
00235                 gss_log(3, "GSS verify error: %s",
00236                         gss_error_tostring(gret, minor, err, sizeof(err)));
00237                 if (gret == GSS_S_DEFECTIVE_TOKEN ||
00238                     gret == GSS_S_BAD_SIG ||
00239                     gret == GSS_S_DUPLICATE_TOKEN ||
00240                     gret == GSS_S_OLD_TOKEN ||
00241                     gret == GSS_S_UNSEQ_TOKEN ||
00242                     gret == GSS_S_GAP_TOKEN ||
00243                     gret == GSS_S_CONTEXT_EXPIRED ||
00244                     gret == GSS_S_NO_CONTEXT ||
00245                     gret == GSS_S_FAILURE)
00246                         return(DST_R_VERIFYFAILURE);
00247                 else
00248                         return (ISC_R_FAILURE);
00249         }
00250 
00251         return (ISC_R_SUCCESS);
00252 }
00253 
00254 static isc_boolean_t
00255 gssapi_compare(const dst_key_t *key1, const dst_key_t *key2) {
00256         gss_ctx_id_t gsskey1 = key1->keydata.gssctx;
00257         gss_ctx_id_t gsskey2 = key2->keydata.gssctx;
00258 
00259         /* No idea */
00260         return (ISC_TF(gsskey1 == gsskey2));
00261 }
00262 
00263 static isc_result_t
00264 gssapi_generate(dst_key_t *key, int unused, void (*callback)(int)) {
00265         UNUSED(key);
00266         UNUSED(unused);
00267         UNUSED(callback);
00268 
00269         /* No idea */
00270         return (ISC_R_FAILURE);
00271 }
00272 
00273 static isc_boolean_t
00274 gssapi_isprivate(const dst_key_t *key) {
00275         UNUSED(key);
00276         return (ISC_TRUE);
00277 }
00278 
00279 static void
00280 gssapi_destroy(dst_key_t *key) {
00281         REQUIRE(key != NULL);
00282         dst_gssapi_deletectx(key->mctx, &key->keydata.gssctx);
00283         key->keydata.gssctx = NULL;
00284 }
00285 
00286 static isc_result_t
00287 gssapi_restore(dst_key_t *key, const char *keystr) {
00288         OM_uint32 major, minor;
00289         unsigned int len;
00290         isc_buffer_t *b = NULL;
00291         isc_region_t r;
00292         gss_buffer_desc gssbuffer;
00293         isc_result_t result;
00294 
00295         len = strlen(keystr);
00296         if ((len % 4) != 0U)
00297                 return (ISC_R_BADBASE64);
00298 
00299         len = (len / 4) * 3;
00300 
00301         result = isc_buffer_allocate(key->mctx, &b, len);
00302         if (result != ISC_R_SUCCESS)
00303                 return (result);
00304 
00305         result = isc_base64_decodestring(keystr, b);
00306         if (result != ISC_R_SUCCESS) {
00307                 isc_buffer_free(&b);
00308                 return (result);
00309         }
00310 
00311         isc_buffer_remainingregion(b, &r);
00312         REGION_TO_GBUFFER(r, gssbuffer);
00313         major = gss_import_sec_context(&minor, &gssbuffer,
00314                                        &key->keydata.gssctx);
00315         if (major != GSS_S_COMPLETE) {
00316                 isc_buffer_free(&b);
00317                 return (ISC_R_FAILURE);
00318         }
00319 
00320         isc_buffer_free(&b);
00321         return (ISC_R_SUCCESS);
00322 }
00323 
00324 static isc_result_t
00325 gssapi_dump(dst_key_t *key, isc_mem_t *mctx, char **buffer, int *length) {
00326         OM_uint32 major, minor;
00327         gss_buffer_desc gssbuffer;
00328         size_t len;
00329         char *buf;
00330         isc_buffer_t b;
00331         isc_region_t r;
00332         isc_result_t result;
00333 
00334         major = gss_export_sec_context(&minor, &key->keydata.gssctx,
00335                                        &gssbuffer);
00336         if (major != GSS_S_COMPLETE) {
00337                 fprintf(stderr, "gss_export_sec_context -> %d, %d\n",
00338                         major, minor);
00339                 return (ISC_R_FAILURE);
00340         }
00341         if (gssbuffer.length == 0U)
00342                 return (ISC_R_FAILURE);
00343         len = ((gssbuffer.length + 2)/3) * 4;
00344         buf = isc_mem_get(mctx, len);
00345         if (buf == NULL) {
00346                 gss_release_buffer(&minor, &gssbuffer);
00347                 return (ISC_R_NOMEMORY);
00348         }
00349         isc_buffer_init(&b, buf, (unsigned int)len);
00350         GBUFFER_TO_REGION(gssbuffer, r);
00351         result = isc_base64_totext(&r, 0, "", &b);
00352         RUNTIME_CHECK(result == ISC_R_SUCCESS);
00353         gss_release_buffer(&minor, &gssbuffer);
00354         *buffer = buf;
00355         *length = (int)len;
00356         return (ISC_R_SUCCESS);
00357 }
00358 
00359 static dst_func_t gssapi_functions = {
00360         gssapi_create_signverify_ctx,
00361         NULL, /*%< createctx2 */
00362         gssapi_destroy_signverify_ctx,
00363         gssapi_adddata,
00364         gssapi_sign,
00365         gssapi_verify,
00366         NULL, /*%< verify2 */
00367         NULL, /*%< computesecret */
00368         gssapi_compare,
00369         NULL, /*%< paramcompare */
00370         gssapi_generate,
00371         gssapi_isprivate,
00372         gssapi_destroy,
00373         NULL, /*%< todns */
00374         NULL, /*%< fromdns */
00375         NULL, /*%< tofile */
00376         NULL, /*%< parse */
00377         NULL, /*%< cleanup */
00378         NULL,  /*%< fromlabel */
00379         gssapi_dump,
00380         gssapi_restore,
00381 };
00382 
00383 isc_result_t
00384 dst__gssapi_init(dst_func_t **funcp) {
00385         REQUIRE(funcp != NULL);
00386         if (*funcp == NULL)
00387                 *funcp = &gssapi_functions;
00388         return (ISC_R_SUCCESS);
00389 }
00390 
00391 #else
00392 int  gssapi_link_unneeded = 1;
00393 #endif
00394 
00395 /*! \file */

Generated on Tue Apr 28 17:40:56 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha