PDNS_ENABLE_VERBOSE_LOGGING
PDNS_ENABLE_PKCS11
-PDNS_ENABLE_GSS_TSIG
AC_SUBST([socketdir])
socketdir="/var/run"
AS_IF([test "x$enable_experimental_pkcs11" = "xyes"],
[AC_MSG_NOTICE([PKCS-11: yes])]
)
-AS_IF([test "x$enable_experimental_gss_tsig" = "xyes"],
- [AC_MSG_NOTICE([GSS-TSIG: yes])]
-)
AS_IF([test "x$enable_lua_records" = "xyes"],
[AC_MSG_NOTICE([LUA records: yes])]
)
GSS-ALLOW-AXFR-PRINCIPAL
------------------------
+ .. versionchanged:: 4.3.1
+ GSS support was removed
Allow this GSS principal to perform AXFR retrieval. Most commonly it is
``host/something@REALM``, ``DNS/something@REALM`` or ``user@REALM``.
GSS-ACCEPTOR-PRINCIPAL
----------------------
+ .. versionchanged:: 4.3.1
+ GSS support was removed
Use this principal for accepting GSS context.
(See :ref:`tsig-gss-tsig`).
GSS-TSIG support
----------------
+ .. versionchanged:: 4.3.1
+ GSS support was removed
GSS-TSIG allows authentication and authorization of DNS updates or AXFR
using Kerberos with TSIG signatures.
+++ /dev/null
-AC_DEFUN([PDNS_ENABLE_GSS_TSIG],[
- AC_MSG_CHECKING([whether to enable experimental GSS-TSIG support])
- AC_ARG_ENABLE([experimental_gss_tsig],
- AS_HELP_STRING([--enable-experimental-gss-tsig],
- [enable experimental GSS-TSIG support @<:@default=no@:>@]
- ),
- [enable_experimental_gss_tsig=$enableval],
- [enable_experimental_gss_tsig=no]
- )
-
- AC_MSG_RESULT([$enable_experimental_gss_tsig])
-
- AM_CONDITIONAL([GSS_TSIG],[test "x$enable_experimental_gss_tsig" != "xno"])
- AC_SUBST(GSS_TSIG)
- AS_IF([test "x$enable_experimental_gss_tsig" != "xno"],
- [PKG_CHECK_MODULES([GSS], [krb5 krb5-gssapi gss],
- [
- AC_DEFINE([ENABLE_GSS_TSIG], [1], [Define to 1 if you want to enable GSS-TSIG support])
- GSS_TSIG=yes
- ],
- [AC_MSG_ERROR([Required libraries for GSS-TSIG not found])]
- )],
- [GSS_TSIG=no])
-])
../../pdns/nameserver.cc \
../../pdns/rcpgenerator.cc \
../../pdns/unix_utility.cc \
- ../../pdns/gss_context.cc ../../pdns/gss_context.hh \
../../pdns/json.hh ../../pdns/json.cc \
../../pdns/shuffle.hh ../../pdns/shuffle.cc \
httpconnector.cc \
$(P11KIT1_CFLAGS)
endif
-if GSS_TSIG
-libtestremotebackend_la_LIBADD += \
- $(GSS_LIBS)
-libtestremotebackend_la_CPPFLAGS+= \
- $(GSS_CFLAGS)
-endif
-
remotebackend_http_test_SOURCES = \
test-remotebackend.cc \
test-remotebackend-http.cc \
AM_CPPFLAGS +=$(LUA_CFLAGS)
endif
-if GSS_TSIG
-AM_CPPFLAGS +=$(GSS_CFLAGS)
-endif
-
if LIBSODIUM
AM_CPPFLAGS +=$(LIBSODIUM_CFLAGS)
endif
dynmessenger.hh \
ednsoptions.cc ednsoptions.hh \
ednssubnet.cc ednssubnet.hh \
- gss_context.cc gss_context.hh \
iputils.cc iputils.hh \
ixfr.cc ixfr.hh \
json.cc json.hh \
pdns_server_LDADD += $(LUA_LIBS)
endif
-if GSS_TSIG
-pdns_server_LDADD += $(GSS_LIBS)
-endif
-
pdnsutil_SOURCES = \
arguments.cc \
auth-caches.cc auth-caches.hh \
dynlistener.cc \
ednsoptions.cc ednsoptions.hh \
ednssubnet.cc \
- gss_context.cc gss_context.hh \
ipcipher.cc ipcipher.hh \
iputils.cc iputils.hh \
json.cc \
pdnsutil_LDADD += $(LUA_LIBS)
endif
-if GSS_TSIG
-pdnsutil_LDADD += $(GSS_LIBS)
-endif
-
zone2sql_SOURCES = \
arguments.cc \
base32.cc \
dnsrecords.cc \
dnssecinfra.cc \
dnswriter.cc dnswriter.hh \
- gss_context.cc gss_context.hh \
iputils.cc \
logger.cc \
misc.cc misc.hh \
saxfr_LDADD += $(P11KIT1_LIBS)
endif
-if GSS_TSIG
-saxfr_LDADD += $(GSS_LIBS)
-endif
-
ixfrdist_SOURCES = \
arguments.cc \
base32.cc \
dnsrecords.cc \
dnssecinfra.cc \
dnswriter.cc dnswriter.hh \
- gss_context.cc gss_context.hh \
iputils.hh iputils.cc \
ixfr.cc ixfr.hh \
ixfrdist.cc \
ixfrdist_LDADD += $(P11KIT1_LIBS)
endif
-if GSS_TSIG
-ixfrdist_LDADD += $(GSS_LIBS)
-endif
-
-
ixplore_SOURCES = \
arguments.cc \
base32.cc \
dnsrecords.cc \
dnssecinfra.cc \
dnswriter.cc dnswriter.hh \
- gss_context.cc gss_context.hh \
iputils.cc \
logger.cc \
misc.cc misc.hh \
ixplore_LDADD += $(P11KIT1_LIBS)
endif
-if GSS_TSIG
-ixplore_LDADD += $(GSS_LIBS)
-endif
-
-
dnstcpbench_SOURCES = \
base32.cc \
base64.cc base64.hh \
dnsrecords.cc \
dnssecinfra.cc \
dnswriter.cc dnswriter.hh \
- gss_context.cc gss_context.hh \
iputils.cc \
logger.cc \
misc.cc misc.hh \
nsec3dig_LDADD += $(P11KIT1_LIBS)
endif
-if GSS_TSIG
-nsec3dig_LDADD += $(GSS_LIBS)
-endif
-
toysdig_SOURCES = \
base32.cc \
base64.cc base64.hh \
dnswriter.cc dnswriter.hh \
ednssubnet.cc ednssubnet.hh \
filterpo.hh \
- gss_context.cc gss_context.hh \
iputils.cc \
logger.cc \
misc.cc misc.hh \
$(LIBCRYPTO_LDFLAGS)
toysdig_LDADD = $(LIBCRYPTO_LIBS)
-if GSS_TSIG
-toysdig_LDADD += $(GSS_LIBS)
-endif
-
if PKCS11
toysdig_SOURCES += pkcs11signers.cc pkcs11signers.hh
toysdig_LDADD += $(P11KIT1_LIBS)
dnsrecords.cc \
dnssecinfra.cc \
dnswriter.cc dnswriter.hh \
- gss_context.cc gss_context.hh \
iputils.cc \
logger.cc \
misc.cc misc.hh \
tsig_tests_LDADD += $(P11KIT1_LIBS)
endif
-if GSS_TSIG
-tsig_tests_LDADD += $(GSS_LIBS)
-endif
-
speedtest_SOURCES = \
base32.cc \
base64.cc base64.hh \
ednscookies.cc ednscookies.hh \
ednssubnet.cc \
gettime.cc gettime.hh \
- gss_context.cc gss_context.hh \
ipcipher.cc ipcipher.hh \
iputils.cc \
ixfr.cc ixfr.hh \
#include "dnssecinfra.hh"
#include "base64.hh"
#include "ednssubnet.hh"
-#include "gss_context.hh"
#include "dns_random.hh"
#include "shuffle.hh"
tt.algo = DNSName("hmac-md5");
string secret64;
- if (tt.algo != DNSName("gss-tsig")) {
- if(!B->getTSIGKey(*keyname, &tt.algo, &secret64)) {
- g_log<<Logger::Error<<"Packet for domain '"<<this->qdomain<<"' denied: can't find TSIG key with name '"<<*keyname<<"' and algorithm '"<<tt.algo<<"'"<<endl;
- return false;
- }
- B64Decode(secret64, *secret);
- tt.secret = *secret;
+ if(!B->getTSIGKey(*keyname, &tt.algo, &secret64)) {
+ g_log<<Logger::Error<<"Packet for domain '"<<this->qdomain<<"' denied: can't find TSIG key with name '"<<*keyname<<"' and algorithm '"<<tt.algo<<"'"<<endl;
+ return false;
}
+ B64Decode(secret64, *secret);
+ tt.secret = *secret;
bool result;
#ifdef HAVE_P11KIT1
#include "pkcs11signers.hh"
#endif
-#include "gss_context.hh"
#include "misc.hh"
using namespace boost::assign;
string toSign = makeTSIGPayload(tsigprevious, reinterpret_cast<const char*>(pw.getContent().data()), pw.getContent().size(), tsigkeyname, trc, timersonly);
if (algo == TSIG_GSS) {
- if (!gss_add_signature(tsigkeyname, toSign, trc.d_mac)) {
- throw PDNSException(string("Could not add TSIG signature with algorithm 'gss-tsig' and key name '")+tsigkeyname.toLogString()+string("'"));
- }
+ throw PDNSException(string("Unsupported TSIG GSS algorithm ") + trc.d_algoName.toLogString());
} else {
trc.d_mac = calculateHMAC(tsigsecret, toSign, algo);
// trc.d_mac[0]++; // sabotage
tsigMsg = makeTSIGMessageFromTSIGPacket(packet, sigPos, tt.name, trc, previousMAC, timersOnly, dnsHeaderOffset);
if (algo == TSIG_GSS) {
- GssContext gssctx(tt.name);
- if (!gss_verify_signature(tt.name, tsigMsg, theirMAC)) {
- throw std::runtime_error("Signature with TSIG key '"+tt.name.toLogString()+"' failed to validate");
- }
+ throw std::runtime_error("Unsupported TSIG GSS algorithm " + trc.d_algoName.toLogString());
} else {
string ourMac = calculateHMAC(tt.secret, tsigMsg, algo);
+++ /dev/null
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include <map>
-#include <string>
-#include "namespaces.hh"
-#include "dns.hh"
-#include "dnsparser.hh"
-#include "dnspacket.hh"
-#include "dnsrecords.hh"
-#include "logger.hh"
-#include "lock.hh"
-#include "arguments.hh"
-
-#include <boost/shared_ptr.hpp>
-#include <boost/make_shared.hpp>
-#include "gss_context.hh"
-
-#ifndef ENABLE_GSS_TSIG
-
-bool GssContext::supported() { return false; }
-GssContext::GssContext() : d_error(GSS_CONTEXT_UNSUPPORTED), d_type(GSS_CONTEXT_NONE) {}
-GssContext::GssContext(const DNSName& label) : d_error(GSS_CONTEXT_UNSUPPORTED), d_type(GSS_CONTEXT_NONE) {}
-void GssContext::setLocalPrincipal(const std::string& name) {}
-bool GssContext::getLocalPrincipal(std::string& name) { return false; }
-void GssContext::setPeerPrincipal(const std::string& name) {}
-bool GssContext::getPeerPrincipal(std::string& name) { return false; }
-void GssContext::generateLabel(const std::string& suffix) {}
-void GssContext::setLabel(const DNSName& label) {}
-bool GssContext::init(const std::string &input, std::string& output) { return false; }
-bool GssContext::accept(const std::string &input, std::string& output) { return false; }
-bool GssContext::destroy() { return false; }
-bool GssContext::expired() { return false; }
-bool GssContext::valid() { return false; }
-bool GssContext::sign(const std::string &input, std::string& output) { return false; }
-bool GssContext::verify(const std::string &input, const std::string &signature) { return false; }
-GssContextError GssContext::getError() { return GSS_CONTEXT_UNSUPPORTED; }
-
-#else
-
-class GssCredential : boost::noncopyable {
-public:
- GssCredential(const std::string& name, const gss_cred_usage_t usage) :
- d_valid(false), d_nameS(name), d_name(GSS_C_NO_NAME), d_cred(GSS_C_NO_CREDENTIAL), d_usage(usage) {
- gss_buffer_desc buffer;
-
- if (name.empty() == false) {
- buffer.length = name.size();
- buffer.value = (void*)name.c_str();
- d_maj = gss_import_name(&d_min, &buffer, (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME, &d_name);
- if (d_maj != GSS_S_COMPLETE) {
- d_valid = false;
- return;
- }
- }
-
- renew();
- };
-
- ~GssCredential() {
- OM_uint32 tmp_maj __attribute__((unused)), tmp_min __attribute__((unused));
- if (d_cred != GSS_C_NO_CREDENTIAL)
- tmp_maj = gss_release_cred(&tmp_min, &d_cred);
- if (d_name != GSS_C_NO_NAME)
- tmp_maj = gss_release_name(&tmp_min, &d_name);
- };
-
- bool expired() const {
- if (d_expires == -1) return false;
- return time((time_t*)NULL)>d_expires;
- }
-
- bool renew() {
- OM_uint32 time_rec, tmp_maj __attribute__((unused)), tmp_min __attribute__((unused));
- d_maj = gss_acquire_cred(&d_min, d_name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, d_usage, &d_cred, NULL, &time_rec);
-
- if (d_maj != GSS_S_COMPLETE) {
- d_valid = false;
- tmp_maj = gss_release_name(&tmp_min, &d_name);
- d_name = GSS_C_NO_NAME;
- return false;
- }
-
- d_valid = true;
-
- if (time_rec > GSS_C_INDEFINITE) {
- d_expires = time((time_t*)NULL)+time_rec;
- } else {
- d_expires = -1;
- }
-
- return true;
- }
-
- bool valid() {
- return d_valid && !expired();
- }
-
- OM_uint32 d_maj,d_min;
-
- bool d_valid;
- int64_t d_expires;
- std::string d_nameS;
- gss_name_t d_name;
- gss_cred_id_t d_cred;
- gss_cred_usage_t d_usage;
-};
-
-std::map<std::string, boost::shared_ptr<GssCredential> > s_gss_accept_creds;
-std::map<std::string, boost::shared_ptr<GssCredential> > s_gss_init_creds;
-
-class GssSecContext : boost::noncopyable {
-public:
- GssSecContext(boost::shared_ptr<GssCredential> cred) {
- if (cred->valid() == false) throw PDNSException("Invalid credential " + cred->d_nameS);
- d_cred = cred;
- d_state = GssStateInitial;
- d_ctx = GSS_C_NO_CONTEXT;
- d_expires = 0;
- d_maj = d_min = 0;
- d_peer_name = GSS_C_NO_NAME;
- d_type = GSS_CONTEXT_NONE;
- }
-
- ~GssSecContext() {
- OM_uint32 tmp_maj __attribute__((unused)), tmp_min __attribute__((unused));
- if (d_ctx != GSS_C_NO_CONTEXT) {
- tmp_maj = gss_delete_sec_context(&tmp_min, &d_ctx, GSS_C_NO_BUFFER);
- }
- if (d_peer_name != GSS_C_NO_NAME) {
- tmp_maj = gss_release_name(&tmp_min, &(d_peer_name));
- }
- }
-
- GssContextType d_type;
- gss_ctx_id_t d_ctx;
- gss_name_t d_peer_name;
- int64_t d_expires;
- boost::shared_ptr<GssCredential> d_cred;
- OM_uint32 d_maj,d_min;
-
- enum {
- GssStateInitial,
- GssStateNegotiate,
- GssStateComplete,
- GssStateError
- } d_state;
-
-};
-
-std::map<DNSName, boost::shared_ptr<GssSecContext> > s_gss_sec_context;
-
-bool GssContext::supported() { return true; }
-
-void GssContext::initialize() {
- d_peerPrincipal = "";
- d_localPrincipal = "";
- d_error = GSS_CONTEXT_NO_ERROR;
- d_type = GSS_CONTEXT_NONE;
-}
-
-GssContext::GssContext() {
- initialize();
- generateLabel("pdns.tsig.");
-}
-
-GssContext::GssContext(const DNSName& label) {
- initialize();
- setLabel(label);
-}
-
-void GssContext::generateLabel(const std::string& suffix) {
- std::ostringstream oss;
- oss << std::hex << time((time_t*)NULL) << "." << suffix;
- setLabel(DNSName(oss.str()));
-}
-
-void GssContext::setLabel(const DNSName& label) {
- d_label = label;
- if (s_gss_sec_context.find(d_label) != s_gss_sec_context.end()) {
- d_ctx = s_gss_sec_context[d_label];
- d_type = d_ctx->d_type;
- }
-}
-
-bool GssContext::expired() {
- return (!d_ctx || (d_ctx->d_expires > -1 && d_ctx->d_expires < time((time_t*)NULL)));
-}
-
-bool GssContext::valid() {
- return (d_ctx && !expired() && d_ctx->d_state == GssSecContext::GssStateComplete);
-}
-
-bool GssContext::init(const std::string &input, std::string& output) {
- OM_uint32 tmp_maj __attribute__((unused)), tmp_min __attribute__((unused));
- OM_uint32 maj,min;
- gss_buffer_desc recv_tok, send_tok, buffer;
- OM_uint32 flags;
- OM_uint32 expires;
-
- boost::shared_ptr<GssCredential> cred;
- if (d_label.empty()) {
- d_error = GSS_CONTEXT_INVALID;
- return false;
- }
-
- d_type = GSS_CONTEXT_INIT;
-
- if (s_gss_init_creds.find(d_localPrincipal) != s_gss_init_creds.end()) {
- cred = s_gss_init_creds[d_localPrincipal];
- } else {
- s_gss_init_creds[d_localPrincipal] = boost::make_shared<GssCredential>(d_localPrincipal, GSS_C_INITIATE);
- cred = s_gss_init_creds[d_localPrincipal];
- }
-
- // see if we can find a context in non-completed state
- if (d_ctx) {
- if (d_ctx->d_state != GssSecContext::GssStateNegotiate) {
- d_error = GSS_CONTEXT_INVALID;
- return false;
- }
- } else {
- // make context
- s_gss_sec_context[d_label] = boost::make_shared<GssSecContext>(cred);
- s_gss_sec_context[d_label]->d_type = d_type;
- d_ctx = s_gss_sec_context[d_label];
- d_ctx->d_state = GssSecContext::GssStateNegotiate;
- }
-
- recv_tok.length = input.size();
- recv_tok.value = (void*)input.c_str();
-
- if (d_peerPrincipal.empty() == false) {
- buffer.value = (void*)d_peerPrincipal.c_str();
- buffer.length = d_peerPrincipal.size();
- maj = gss_import_name(&min, &buffer, (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME, &(d_ctx->d_peer_name));
- if (maj != GSS_S_COMPLETE) {
- processError("gss_import_name", maj, min);
- return false;
- }
- }
-
- maj = gss_init_sec_context(&min, cred->d_cred, &(d_ctx->d_ctx), d_ctx->d_peer_name, GSS_C_NO_OID, GSS_C_MUTUAL_FLAG|GSS_C_REPLAY_FLAG, GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS, &recv_tok, NULL, &send_tok, &flags, &expires);
-
- if (send_tok.length>0) {
- output.assign((const char*)send_tok.value, send_tok.length);
- tmp_maj = gss_release_buffer(&tmp_min, &send_tok);
- }
-
- if (maj == GSS_S_COMPLETE) {
- if (expires > GSS_C_INDEFINITE) {
- d_ctx->d_expires = time((time_t*)NULL) + expires;
- } else {
- d_ctx->d_expires = -1;
- }
- d_ctx->d_state = GssSecContext::GssStateComplete;
- return true;
- } else if (maj != GSS_S_CONTINUE_NEEDED) {
- processError("gss_init_sec_context", maj,min);
- }
-
- return (maj == GSS_S_CONTINUE_NEEDED);
-}
-
-bool GssContext::accept(const std::string &input, std::string& output) {
- OM_uint32 tmp_maj __attribute__((unused)), tmp_min __attribute__((unused));
- OM_uint32 maj,min;
- gss_buffer_desc recv_tok, send_tok;
- OM_uint32 flags;
- OM_uint32 expires;
-
- boost::shared_ptr<GssCredential> cred;
- if (d_label.empty()) {
- d_error = GSS_CONTEXT_INVALID;
- return false;
- }
-
- d_type = GSS_CONTEXT_ACCEPT;
-
- if (s_gss_accept_creds.find(d_localPrincipal) != s_gss_accept_creds.end()) {
- cred = s_gss_accept_creds[d_localPrincipal];
- } else {
- s_gss_accept_creds[d_localPrincipal] = boost::make_shared<GssCredential>(d_localPrincipal, GSS_C_ACCEPT);
- cred = s_gss_accept_creds[d_localPrincipal];
- }
-
- // see if we can find a context in non-completed state
- if (d_ctx) {
- if (d_ctx->d_state != GssSecContext::GssStateNegotiate) {
- d_error = GSS_CONTEXT_INVALID;
- return false;
- }
- } else {
- // make context
- s_gss_sec_context[d_label] = boost::make_shared<GssSecContext>(cred);
- s_gss_sec_context[d_label]->d_type = d_type;
- d_ctx = s_gss_sec_context[d_label];
- d_ctx->d_state = GssSecContext::GssStateNegotiate;
- }
-
- recv_tok.length = input.size();
- recv_tok.value = (void*)input.c_str();
-
- maj = gss_accept_sec_context(&min, &(d_ctx->d_ctx), cred->d_cred, &recv_tok, GSS_C_NO_CHANNEL_BINDINGS, &(d_ctx->d_peer_name), NULL, &send_tok, &flags, &expires, NULL);
-
- if (send_tok.length>0) {
- output.assign((const char*)send_tok.value, send_tok.length);
- tmp_maj = gss_release_buffer(&tmp_min, &send_tok);
- }
-
- if (maj == GSS_S_COMPLETE) {
- if (expires > GSS_C_INDEFINITE) {
- d_ctx->d_expires = time((time_t*)NULL) + expires;
- } else {
- d_ctx->d_expires = -1;
- }
- d_ctx->d_state = GssSecContext::GssStateComplete;
- return true;
- } else if (maj != GSS_S_CONTINUE_NEEDED) {
- processError("gss_accept_sec_context", maj,min);
- }
- return (maj == GSS_S_CONTINUE_NEEDED);
-};
-
-bool GssContext::sign(const std::string& input, std::string& output) {
- OM_uint32 tmp_maj __attribute__((unused)), tmp_min __attribute__((unused));
- OM_uint32 maj,min;
-
- gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER;
- gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
-
- recv_tok.length = input.size();
- recv_tok.value = (void*)input.c_str();
-
- maj = gss_get_mic(&min, d_ctx->d_ctx, GSS_C_QOP_DEFAULT, &recv_tok, &send_tok);
-
- if (send_tok.length>0) {
- output.assign((const char*)send_tok.value, send_tok.length);
- tmp_maj = gss_release_buffer(&tmp_min, &send_tok);
- }
-
- if (maj != GSS_S_COMPLETE) {
- processError("gss_get_mic", maj,min);
- }
-
- return (maj == GSS_S_COMPLETE);
-}
-
-bool GssContext::verify(const std::string& input, const std::string& signature) {
- OM_uint32 maj,min;
-
- gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER;
- gss_buffer_desc sign_tok = GSS_C_EMPTY_BUFFER;
-
- recv_tok.length = input.size();
- recv_tok.value = (void*)input.c_str();
- sign_tok.length = signature.size();
- sign_tok.value = (void*)signature.c_str();
-
- maj = gss_verify_mic(&min, d_ctx->d_ctx, &recv_tok, &sign_tok, NULL);
-
- if (maj != GSS_S_COMPLETE) {
- processError("gss_get_mic", maj,min);
- }
-
- return (maj == GSS_S_COMPLETE);
-}
-
-bool GssContext::destroy() {
- return false;
-}
-
-void GssContext::setLocalPrincipal(const std::string& name) {
- d_localPrincipal = name;
-}
-
-bool GssContext::getLocalPrincipal(std::string& name) {
- name = d_localPrincipal;
- return name.size()>0;
-}
-
-void GssContext::setPeerPrincipal(const std::string& name) {
- d_peerPrincipal = name;
-}
-
-bool GssContext::getPeerPrincipal(std::string& name) {
- gss_buffer_desc value;
- OM_uint32 maj,min;
-
- if (d_ctx->d_peer_name != GSS_C_NO_NAME) {
- maj = gss_display_name(&min, d_ctx->d_peer_name, &value, NULL);
- if (maj == GSS_S_COMPLETE && value.length > 0) {
- name.assign((const char*)value.value, value.length);
- maj = gss_release_buffer(&min, &value);
- return true;
- } else {
- return false;
- }
- } else {
- return false;
- }
-}
-
-void GssContext::processError(const std::string& method, OM_uint32 maj, OM_uint32 min) {
- OM_uint32 tmp_min;
- gss_buffer_desc msg;
- OM_uint32 msg_ctx;
-
- msg_ctx = 0;
- while (1) {
- ostringstream oss;
- gss_display_status(&tmp_min, maj, GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &msg);
- oss << method << ": " << (char*)msg.value;
- d_gss_errors.push_back(oss.str());
- if (!msg_ctx) break;
- }
- msg_ctx = 0;
- while (1) {
- ostringstream oss;
- gss_display_status(&tmp_min, min, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &msg);
- oss << method << ": " << (char*)msg.value;
- d_gss_errors.push_back(oss.str());
- if (!msg_ctx) break;
- }
-}
-
-#endif
-
-bool gss_add_signature(const DNSName& context, const std::string& message, std::string& mac) {
- string tmp_mac;
- GssContext gssctx(context);
- if (!gssctx.valid()) {
- g_log<<Logger::Error<<"GSS context '"<<context<<"' is not valid"<<endl;
- for(const string& error : gssctx.getErrorStrings()) {
- g_log<<Logger::Error<<"GSS error: "<<error<<endl;;
- }
- return false;
- }
-
- if (!gssctx.sign(message, tmp_mac)) {
- g_log<<Logger::Error<<"Could not sign message using GSS context '"<<context<<"'"<<endl;
- for(const string& error : gssctx.getErrorStrings()) {
- g_log<<Logger::Error<<"GSS error: "<<error<<endl;;
- }
- return false;
- }
- mac = tmp_mac;
- return true;
-}
-
-bool gss_verify_signature(const DNSName& context, const std::string& message, const std::string& mac) {
- GssContext gssctx(context);
- if (!gssctx.valid()) {
- g_log<<Logger::Error<<"GSS context '"<<context<<"' is not valid"<<endl;
- for(const string& error : gssctx.getErrorStrings()) {
- g_log<<Logger::Error<<"GSS error: "<<error<<endl;;
- }
- return false;
- }
-
- if (!gssctx.verify(message, mac)) {
- g_log<<Logger::Error<<"Could not verify message using GSS context '"<<context<<"'"<<endl;
- for(const string& error : gssctx.getErrorStrings()) {
- g_log<<Logger::Error<<"GSS error: "<<error<<endl;;
- }
- return false;
- }
- return true;
-}
+++ /dev/null
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#pragma once
-
-#ifdef ENABLE_GSS_TSIG
-#include <gssapi/gssapi.h>
-#include <gssapi/gssapi_krb5.h>
-#include <gssapi/gssapi_ext.h>
-#endif
-
-//! Generic errors
-enum GssContextError {
- GSS_CONTEXT_NO_ERROR,
- GSS_CONTEXT_UNSUPPORTED,
- GSS_CONTEXT_NOT_FOUND,
- GSS_CONTEXT_NOT_INITIALIZED,
- GSS_CONTEXT_INVALID,
- GSS_CONTEXT_EXPIRED,
- GSS_CONTEXT_ALREADY_INITIALIZED
-};
-
-//! GSS context types
-enum GssContextType {
- GSS_CONTEXT_NONE,
- GSS_CONTEXT_INIT,
- GSS_CONTEXT_ACCEPT
-};
-
-class GssSecContext;
-
-/*! Class for representing GSS names, such as host/host.domain.com@REALM.
-*/
-class GssName {
-public:
- //! Initialize to empty name
- GssName() {
- setName("");
- };
-
- //! Initialize using specific name
- GssName(const std::string& name) {
- setName(name);
- };
-
- //! Parse name into native representation
- bool setName(const std::string& name) {
-#ifdef ENABLE_GSS_TSIG
- gss_buffer_desc buffer;
- d_name = GSS_C_NO_NAME;
-
- if (!name.empty()) {
- buffer.length = name.size();
- buffer.value = (void*)name.c_str();
- d_maj = gss_import_name(&d_min, &buffer, (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME, &d_name);
- return d_maj == GSS_S_COMPLETE;
- }
-
- return true;
-#endif
- return false;
- };
-
- ~GssName() {
-#ifdef ENABLE_GSS_TSIG
- if (d_name != GSS_C_NO_NAME)
- gss_release_name(&d_min, &d_name);
-#endif
- };
-
- //! Compare two Gss Names, if no gss support is compiled in, returns false always
- //! This is not necessarily same as string comparison between two non-parsed names
- bool operator==(const GssName& rhs) {
-#ifdef ENABLE_GSS_TSIG
- OM_uint32 maj,min;
- int result;
- maj = gss_compare_name(&min, d_name, rhs.d_name, &result);
- return (maj == GSS_S_COMPLETE && result != 0);
-#endif
- return false;
- }
-
- //! Compare two Gss Names, if no gss support is compiled in, returns false always
- //! This is not necessarily same as string comparison between two non-parsed names
- bool match(const std::string& name) {
-#ifdef ENABLE_GSS_TSIG
- OM_uint32 maj,min;
- int result;
- gss_name_t comp;
- gss_buffer_desc buffer;
- buffer.length = name.size();
- buffer.value = (void*)name.c_str();
- maj = gss_import_name(&min, &buffer, (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME, &comp);
- if (maj != GSS_S_COMPLETE)
- throw PDNSException("Could not import " + name + ": " + std::to_string(maj) + string(",") + std::to_string(min));
- // do comparison
- maj = gss_compare_name(&min, d_name, comp, &result);
- gss_release_name(&min, &comp);
- return (maj == GSS_S_COMPLETE && result != 0);
-#else
- return false;
-#endif
- };
-
- //! Check if GSS name was parsed successfully.
- bool valid() {
-#ifdef ENABLE_GSS_TSIG
- return d_maj == GSS_S_COMPLETE;
-#else
- return false;
-#endif
- }
-private:
-#ifdef ENABLE_GSS_TSIG
- OM_uint32 d_maj,d_min;
- gss_name_t d_name;
-#endif
-};
-
-class GssContext {
-public:
- static bool supported(); //<! Returns true if GSS is supported in the first place
- GssContext(); //<! Construct new GSS context with random name
- GssContext(const DNSName& label); //<! Create or open existing named context
-
- void setLocalPrincipal(const std::string& name); //<! Set our gss name
- bool getLocalPrincipal(std::string& name); //<! Get our name
- void setPeerPrincipal(const std::string& name); //<! Set remote name (do not use after negotiation)
- bool getPeerPrincipal(std::string &name); //<! Return remote name, returns actual name after negotiation
-
- void generateLabel(const std::string& suffix); //<! Generate random context name using suffix (such as mydomain.com)
- void setLabel(const DNSName& label); //<! Set context name to this label
- const DNSName& getLabel() { return d_label; } //<! Return context name
-
- bool init(const std::string &input, std::string& output); //<! Perform GSS Initiate Security Context handshake
- bool accept(const std::string &input, std::string& output); //<! Perform GSS Accept Security Context handshake
- bool destroy(); //<! Release the cached context
- bool expired(); //<! Check if context is expired
- bool valid(); //<! Check if context is valid
-
- bool sign(const std::string &input, std::string& output); //<! Sign something using gss
- bool verify(const std::string &input, const std::string &signature); //<! Validate gss signature with something
-
- GssContextError getError(); //<! Get error
- const std::vector<std::string> getErrorStrings() { return d_gss_errors; } //<! Get native error texts
- private:
- void release(); //<! Release context
- void initialize(); //<! Initialize context
-#ifdef ENABLE_GSS_TSIG
- void processError(const string& method, OM_uint32 maj, OM_uint32 min); //<! Process and fill error text vector
-#endif
- DNSName d_label; //<! Context name
- std::string d_peerPrincipal; //<! Remote name
- std::string d_localPrincipal; //<! Our name
- GssContextError d_error; //<! Context error
- GssContextType d_type; //<! Context type
- std::vector<std::string> d_gss_errors; //<! Native error string(s)
- boost::shared_ptr<GssSecContext> d_ctx; //<! Attached security context
-};
-
-bool gss_add_signature(const DNSName& context, const std::string& message, std::string& mac); //<! Create signature
-bool gss_verify_signature(const DNSName& context, const std::string& message, const std::string& mac); //<! Validate signature
#include "dnssecinfra.hh"
#include "dns_random.hh"
-#include "gss_context.hh"
#include <boost/multi_index_container.hpp>
#include "axfr-retriever.hh"
#include <fstream>
return r;
} else {
getTSIGHashEnum(trc.d_algoName, p.d_tsig_algo);
- if (p.d_tsig_algo == TSIG_GSS) {
- GssContext gssctx(keyname);
- if (!gssctx.getPeerPrincipal(p.d_peer_principal)) {
- g_log<<Logger::Warning<<"Failed to extract peer principal from GSS context with keyname '"<<keyname<<"'"<<endl;
- }
- }
}
p.setTSIGDetails(trc, keyname, secret, trc.d_mac); // this will get copied by replyPacket()
noCache=true;
#include "packetcache.hh"
#include "dnsseckeeper.hh"
#include "lua-auth4.hh"
-#include "gss_context.hh"
#include "namespaces.hh"
DNSName zone(cmds[1]);
string kind = cmds[2];
static vector<string> multiMetaWhitelist = {"ALLOW-AXFR-FROM", "ALLOW-DNSUPDATE-FROM",
- "ALSO-NOTIFY", "TSIG-ALLOW-AXFR", "TSIG-ALLOW-DNSUPDATE", "GSS-ALLOW-AXFR-PRINCIPAL",
+ "ALSO-NOTIFY", "TSIG-ALLOW-AXFR", "TSIG-ALLOW-DNSUPDATE",
"PUBLISH-CDS"};
bool clobber = true;
if (cmds[0] == "add-meta") {
filterpo.cc filterpo.hh \
fstrm_logger.cc fstrm_logger.hh \
gettime.cc gettime.hh \
- gss_context.cc gss_context.hh \
iputils.hh iputils.cc \
ixfr.cc ixfr.hh \
json.cc json.hh \
ednssubnet.cc ednssubnet.hh \
filterpo.cc filterpo.hh \
gettime.cc gettime.hh \
- gss_context.cc gss_context.hh \
iputils.cc iputils.hh \
ixfr.cc ixfr.hh \
logger.cc logger.hh \
+++ /dev/null
-../gss_context.cc
\ No newline at end of file
+++ /dev/null
-../gss_context.hh
\ No newline at end of file
#include "dns_random.hh"
#include <poll.h>
-#include "gss_context.hh"
#include "namespaces.hh"
using pdns::resolver::parseResult;
return RCode::Refused;
}
- if (p.d_tsig_algo == TSIG_GSS) {
- GssName inputname(p.d_peer_principal); // match against principal since GSS
- for(const auto& key: tsigKeys) {
- if (inputname.match(key)) {
- validKey = true;
- break;
- }
- }
- } else {
- for(const auto& key: tsigKeys) {
- if (inputkey == DNSName(key)) { // because checkForCorrectTSIG has already been performed earlier on, if the names of the ky match with the domain given. THis is valid.
- validKey=true;
- break;
- }
+ for(const auto& key: tsigKeys) {
+ if (inputkey == DNSName(key)) { // because checkForCorrectTSIG has already been performed earlier on, if the names of the ky match with the domain given. THis is valid.
+ validKey=true;
+ break;
}
}
#include "dnssecinfra.hh"
#include "dns_random.hh"
-#include "gss_context.hh"
StatBag S;
try
{
if(argc < 4) {
- cerr<<"Syntax: saxfr IP-address port zone [showdetails] [showflags] [unhash] [gss:remote-principal] [tsig:keyname:algo:secret]"<<endl;
+ cerr<<"Syntax: saxfr IP-address port zone [showdetails] [showflags] [unhash] [tsig:keyname:algo:secret]"<<endl;
exit(EXIT_FAILURE);
}
bool showdetails=false;
bool showflags=false;
bool unhash=false;
- bool gss=false;
bool tsig=false;
TSIGHashEnum tsig_algo;
DNSName tsig_key;
showflags=true;
if (strcmp(argv[i], "unhash") == 0)
unhash=true;
- if (strncmp(argv[i], "gss:",4) == 0) {
- gss=true;
- tsig=true;
- tsig_algo=TSIG_GSS;
- remote_principal = string(argv[i]+4);
- if (remote_principal.empty()) {
- cerr<<"Remote principal is required"<<endl;
- exit(EXIT_FAILURE);
- }
- }
if (strncmp(argv[i], "tsig:",5) == 0) {
vector<string> parts;
tsig=true;
Socket sock(dest.sin4.sin_family, SOCK_STREAM);
sock.connect(dest);
- if (gss) {
-#ifndef ENABLE_GSS_TSIG
- cerr<<"No GSS support compiled in"<<endl;
- exit(EXIT_FAILURE);
-#else
- string input,output;
- GssContext gssctx;
- gssctx.generateLabel(argv[3]);
- gssctx.setPeerPrincipal(remote_principal);
-
- while(gssctx.init(input, output) && gssctx.valid() == false) {
- input="";
- DNSPacketWriter pwtkey(packet, gssctx.getLabel(), QType::TKEY, QClass::ANY);
- TKEYRecordContent tkrc;
- tkrc.d_algo = DNSName("gss-tsig.");
- tkrc.d_inception = time((time_t*)NULL);
- tkrc.d_expiration = tkrc.d_inception+15;
- tkrc.d_mode = 3;
- tkrc.d_error = 0;
- tkrc.d_keysize = output.size();
- tkrc.d_key = output;
- tkrc.d_othersize = 0;
- pwtkey.getHeader()->id = dns_random_uint16();
- pwtkey.startRecord(gssctx.getLabel(), QType::TKEY, 3600, QClass::ANY, DNSResourceRecord::ADDITIONAL, false);
- tkrc.toPacket(pwtkey);
- pwtkey.commit();
- for(const string& msg : gssctx.getErrorStrings()) {
- cerr<<msg<<endl;
- }
-
- len = htons(packet.size());
- if(sock.write((char *) &len, 2) != 2)
- throw PDNSException("tcp write failed");
- sock.writen(string((char*)&packet[0], packet.size()));
- if(sock.read((char *) &len, 2) != 2)
- throw PDNSException("tcp read failed");
-
- len=ntohs(len);
- std::unique_ptr<char[]> creply(new char[len]);
- int n=0;
- int numread;
- while(n<len) {
- numread=sock.read(creply.get()+n, len-n);
- if(numread<0)
- throw PDNSException("tcp read failed");
- n+=numread;
- }
-
- MOADNSParser mdp(false, string(creply.get(), len));
- if (mdp.d_header.rcode != 0) {
- throw PDNSException(string("Remote server refused: ") + std::to_string(mdp.d_header.rcode));
- }
- for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
- if(i->first.d_type != QType::TKEY) continue;
- // recover TKEY record
- tkrc = TKEYRecordContent(i->first.d_content->getZoneRepresentation());
- input = tkrc.d_key;
- }
- }
-
- if (gssctx.valid() == false) {
- cerr<<"Could not create GSS context"<<endl;
- exit(EXIT_FAILURE);
- }
-
- tsig_key = DNSName(gssctx.getLabel());
-#endif
- }
-
DNSPacketWriter pw(packet, DNSName(argv[3]), 252);
pw.getHeader()->id = dns_random_uint16();
return false;
} else {
getTSIGHashEnum(trc.d_algoName, q->d_tsig_algo);
- if (q->d_tsig_algo == TSIG_GSS) {
- GssContext gssctx(keyname);
- if (!gssctx.getPeerPrincipal(q->d_peer_principal)) {
- g_log<<Logger::Warning<<"Failed to extract peer principal from GSS context with keyname '"<<keyname<<"'"<<endl;
- }
- }
}
DNSSECKeeper dk(s_P->getBackend());
-
- if (q->d_tsig_algo == TSIG_GSS) {
- vector<string> princs;
- s_P->getBackend()->getDomainMetadata(q->qdomain, "GSS-ALLOW-AXFR-PRINCIPAL", princs);
- for(const std::string& princ : princs) {
- if (q->d_peer_principal == princ) {
- g_log<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: TSIG signed request with authorized principal '"<<q->d_peer_principal<<"' and algorithm 'gss-tsig'"<<endl;
- return true;
- }
- }
- g_log<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' denied: TSIG signed request with principal '"<<q->d_peer_principal<<"' and algorithm 'gss-tsig' is not permitted"<<endl;
- return false;
- }
-
if(!dk.TSIGGrantsAccess(q->qdomain, keyname)) {
g_log<<Logger::Error<<"AXFR '"<<q->qdomain<<"' denied: key with name '"<<keyname<<"' and algorithm '"<<getTSIGAlgoName(q->d_tsig_algo)<<"' does not grant access to zone"<<endl;
return false;
DNSName algorithm=trc.d_algoName; // FIXME400: check
if (algorithm == DNSName("hmac-md5.sig-alg.reg.int"))
algorithm = DNSName("hmac-md5");
- if (algorithm != DNSName("gss-tsig")) {
- if(!db.getTSIGKey(tsigkeyname, &algorithm, &tsig64)) {
- g_log<<Logger::Error<<"TSIG key '"<<tsigkeyname<<"' for domain '"<<target<<"' not found"<<endl;
- return 0;
- }
- if (B64Decode(tsig64, tsigsecret) == -1) {
- g_log<<Logger::Error<<"Unable to Base-64 decode TSIG key '"<<tsigkeyname<<"' for domain '"<<target<<"'"<<endl;
- return 0;
- }
+
+ if(!db.getTSIGKey(tsigkeyname, &algorithm, &tsig64)) {
+ g_log<<Logger::Error<<"TSIG key '"<<tsigkeyname<<"' for domain '"<<target<<"' not found"<<endl;
+ return 0;
+ }
+ if (B64Decode(tsig64, tsigsecret) == -1) {
+ g_log<<Logger::Error<<"Unable to Base-64 decode TSIG key '"<<tsigkeyname<<"' for domain '"<<target<<"'"<<endl;
+ return 0;
}
}
TKEYRecordContent tkey_in;
std::shared_ptr<TKEYRecordContent> tkey_out(new TKEYRecordContent());
DNSName name;
- bool sign = false;
if (!p.getTKEYRecord(&tkey_in, &name)) {
g_log<<Logger::Error<<"TKEY request but no TKEY RR found"<<endl;
tkey_out->d_inception = time((time_t*)NULL);
tkey_out->d_expiration = tkey_out->d_inception+15;
- GssContext ctx(name);
-
if (tkey_in.d_mode == 3) { // establish context
if (tkey_in.d_algo == DNSName("gss-tsig.")) {
- std::vector<std::string> meta;
- DNSName tmpName(name);
- do {
- if (B.getDomainMetadata(tmpName, "GSS-ACCEPTOR-PRINCIPAL", meta) && meta.size()>0) {
- break;
- }
- } while(tmpName.chopOff());
-
- if (meta.size()>0) {
- ctx.setLocalPrincipal(meta[0]);
- }
- // try to get a context
- if (!ctx.accept(tkey_in.d_key, tkey_out->d_key))
- tkey_out->d_error = 19;
- else
- sign = true;
+ tkey_out->d_error = 19;
} else {
tkey_out->d_error = 21; // BADALGO
}
r->setRcode(RCode::NotAuth);
return;
}
- if (ctx.valid())
- ctx.destroy();
- else
- tkey_out->d_error = 20; // BADNAME (because we have no support for anything here)
+
+ tkey_out->d_error = 20; // BADNAME (because we have no support for anything here)
} else {
if (p.d_havetsig == false && tkey_in.d_mode != 2) { // unauthenticated
if (p.d.opcode == Opcode::Update)
zrr.dr.d_content = tkey_out;
zrr.dr.d_place = DNSResourceRecord::ANSWER;
r->addRecord(std::move(zrr));
-
- if (sign)
- {
- TSIGRecordContent trc;
- trc.d_algoName = DNSName("gss-tsig");
- trc.d_time = tkey_out->d_inception;
- trc.d_fudge = 300;
- trc.d_mac = "";
- trc.d_origID = p.d.id;
- trc.d_eRcode = 0;
- trc.d_otherData = "";
- // this should cause it to lookup name context
- r->setTSIGDetails(trc, name, name.toStringNoDot(), "", false);
- }
-
r->commitD();
}
#include "tsigverifier.hh"
#include "dnssecinfra.hh"
-#include "gss_context.hh"
bool TSIGTCPVerifier::check(const string& data, const MOADNSParser& mdp)
{
"NOTIFY-DNSUPDATE",
"ALSO-NOTIFY",
"AXFR-MASTER-TSIG",
- "GSS-ALLOW-AXFR-PRINCIPAL",
- "GSS-ACCEPTOR-PRINCIPAL",
"IXFR",
"LUA-AXFR-SCRIPT",
"NSEC3NARROW",