00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00061
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
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
00103
00104
00105
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
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
00149
00150
00151 isc_buffer_usedregion(ctx->buffer, &message);
00152 REGION_TO_GBUFFER(message, gmessage);
00153
00154
00155
00156
00157 gret = gss_get_mic(&minor, gssctx, GSS_C_QOP_DEFAULT, &gmessage,
00158 &gsig);
00159
00160
00161
00162
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
00172
00173
00174 if (gsig.length > isc_buffer_availablelength(sig)) {
00175 gss_release_buffer(&minor, &gsig);
00176 return (ISC_R_NOSPACE);
00177 }
00178
00179
00180
00181
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
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
00205
00206
00207 isc_buffer_usedregion(ctx->buffer, &message);
00208 REGION_TO_GBUFFER(message, gmessage);
00209
00210
00211
00212
00213
00214
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
00226
00227 gret = gss_verify_mic(&minor, gssctx, &gmessage, &gsig, NULL);
00228
00229 isc_mem_free(dst__memory_pool, buf);
00230
00231
00232
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
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
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,
00362 gssapi_destroy_signverify_ctx,
00363 gssapi_adddata,
00364 gssapi_sign,
00365 gssapi_verify,
00366 NULL,
00367 NULL,
00368 gssapi_compare,
00369 NULL,
00370 gssapi_generate,
00371 gssapi_isprivate,
00372 gssapi_destroy,
00373 NULL,
00374 NULL,
00375 NULL,
00376 NULL,
00377 NULL,
00378 NULL,
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