static isc_result_t process_gsstkey(dns_name_t *name, dns_rdata_tkey_t *tkeyin, dns_tkeyctx_t *tctx, dns_rdata_tkey_t *tkeyout, dns_tsig_keyring_t *ring) { isc_result_t result = ISC_R_SUCCESS; dst_key_t *dstkey = NULL; dns_tsigkey_t *tsigkey = NULL; dns_fixedname_t principal; isc_stdtime_t now; isc_region_t intoken; isc_buffer_t *outtoken = NULL; gss_ctx_id_t gss_ctx = NULL; /* * You have to define either a gss credential (principal) to * accept with tkey-gssapi-credential, or you have to * configure a specific keytab (with tkey-gssapi-keytab) in * order to use gsstkey */ if (tctx->gsscred == NULL && tctx->gssapi_keytab == NULL) { tkey_log("process_gsstkey(): no tkey-gssapi-credential " "or tkey-gssapi-keytab configured"); return (ISC_R_NOPERM); } if (!dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPI_NAME) && !dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPIMS_NAME)) { tkeyout->error = dns_tsigerror_badalg; tkey_log("process_gsstkey(): dns_tsigerror_badalg"); /* XXXSRA */ return (ISC_R_SUCCESS); } /* * XXXDCL need to check for key expiry per 4.1.1 * XXXDCL need a way to check fully established, perhaps w/key_flags */ intoken.base = tkeyin->key; intoken.length = tkeyin->keylen; result = dns_tsigkey_find(&tsigkey, name, &tkeyin->algorithm, ring); if (result == ISC_R_SUCCESS) gss_ctx = dst_key_getgssctx(tsigkey->key); dns_fixedname_init(&principal); /* * Note that tctx->gsscred may be NULL if tctx->gssapi_keytab is set */ result = dst_gssapi_acceptctx(tctx->gsscred, tctx->gssapi_keytab, &intoken, &outtoken, &gss_ctx, dns_fixedname_name(&principal), tctx->mctx); if (result == DNS_R_INVALIDTKEY) { if (tsigkey != NULL) dns_tsigkey_detach(&tsigkey); tkeyout->error = dns_tsigerror_badkey; tkey_log("process_gsstkey(): dns_tsigerror_badkey"); /* XXXSRA */ return (ISC_R_SUCCESS); } if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS) goto failure; /* * XXXDCL Section 4.1.3: Limit GSS_S_CONTINUE_NEEDED to 10 times. */ isc_stdtime_get(&now); if (tsigkey == NULL) { #ifdef GSSAPI OM_uint32 gret, minor, lifetime; #endif isc_uint32_t expire; RETERR(dst_key_fromgssapi(name, gss_ctx, ring->mctx, &dstkey, &intoken)); /* * Limit keys to 1 hour or the context's lifetime whichever * is smaller. */ expire = now + 3600; #ifdef GSSAPI gret = gss_context_time(&minor, gss_ctx, &lifetime); if (gret == GSS_S_COMPLETE && now + lifetime < expire) expire = now + lifetime; #endif RETERR(dns_tsigkey_createfromkey(name, &tkeyin->algorithm, dstkey, ISC_TRUE, dns_fixedname_name(&principal), now, expire, ring->mctx, ring, NULL)); dst_key_free(&dstkey); tkeyout->inception = now; tkeyout->expire = expire; } else { tkeyout->inception = tsigkey->inception; tkeyout->expire = tsigkey->expire; dns_tsigkey_detach(&tsigkey); } if (outtoken) { tkeyout->key = isc_mem_get(tkeyout->mctx, isc_buffer_usedlength(outtoken)); if (tkeyout->key == NULL) { result = ISC_R_NOMEMORY; goto failure; } tkeyout->keylen = isc_buffer_usedlength(outtoken); memmove(tkeyout->key, isc_buffer_base(outtoken), isc_buffer_usedlength(outtoken)); isc_buffer_free(&outtoken); } else { tkeyout->key = isc_mem_get(tkeyout->mctx, tkeyin->keylen); if (tkeyout->key == NULL) { result = ISC_R_NOMEMORY; goto failure; } tkeyout->keylen = tkeyin->keylen; memmove(tkeyout->key, tkeyin->key, tkeyin->keylen); } tkeyout->error = dns_rcode_noerror; tkey_log("process_gsstkey(): dns_tsigerror_noerror"); /* XXXSRA */ return (ISC_R_SUCCESS); failure: if (tsigkey != NULL) dns_tsigkey_detach(&tsigkey); if (dstkey != NULL) dst_key_free(&dstkey); if (outtoken != NULL) isc_buffer_free(&outtoken); tkey_log("process_gsstkey(): %s", isc_result_totext(result)); /* XXXSRA */ return (result); }
static isc_result_t process_gsstkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name, dns_rdata_tkey_t *tkeyin, dns_tkeyctx_t *tctx, dns_rdata_tkey_t *tkeyout, dns_tsig_keyring_t *ring, dns_namelist_t *namelist) { isc_result_t result = ISC_R_SUCCESS; dst_key_t *dstkey = NULL; void *gssctx = NULL; isc_stdtime_t now; isc_region_t intoken; unsigned char array[1024]; isc_buffer_t outtoken; UNUSED(namelist); if (tctx->gsscred == NULL) return (ISC_R_NOPERM); if (!dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPI_NAME) && !dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPIMS_NAME)) { tkeyout->error = dns_tsigerror_badalg; return (ISC_R_SUCCESS); } intoken.base = tkeyin->key; intoken.length = tkeyin->keylen; isc_buffer_init(&outtoken, array, sizeof(array)); RETERR(dst_gssapi_acceptctx(name, tctx->gsscred, &intoken, &outtoken, &gssctx)); dstkey = NULL; RETERR(dst_key_fromgssapi(name, gssctx, msg->mctx, &dstkey)); result = dns_tsigkey_createfromkey(name, &tkeyin->algorithm, dstkey, ISC_TRUE, signer, tkeyin->inception, tkeyin->expire, msg->mctx, ring, NULL); #if 1 if (result != ISC_R_SUCCESS) goto failure; #else if (result == ISC_R_NOTFOUND) { tkeyout->error = dns_tsigerror_badalg; return (ISC_R_SUCCESS); } if (result != ISC_R_SUCCESS) goto failure; #endif /* This key is good for a long time */ isc_stdtime_get(&now); tkeyout->inception = tkeyin->inception; tkeyout->expire = tkeyin->expire; tkeyout->key = isc_mem_get(msg->mctx, isc_buffer_usedlength(&outtoken)); if (tkeyout->key == NULL) { result = ISC_R_NOMEMORY; goto failure; } tkeyout->keylen = isc_buffer_usedlength(&outtoken); memcpy(tkeyout->key, isc_buffer_base(&outtoken), tkeyout->keylen); return (ISC_R_SUCCESS); failure: if (dstkey != NULL) dst_key_free(&dstkey); return (result); }