From: Bert Hubert Date: Mon, 27 Dec 2010 15:56:20 +0000 (+0000) Subject: move to mature key management (unified zsks, proper ids, active, inactive) X-Git-Tag: auth-3.0~490 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bed962b550caa1616e4150c7805760763ef87dd9;p=pdns move to mature key management (unified zsks, proper ids, active, inactive) git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@1757 d19b8d6e-7fed-0310-83ef-9ca221ded41b --- diff --git a/pdns/Makefile.am b/pdns/Makefile.am index ae60dc868..44d04f363 100644 --- a/pdns/Makefile.am +++ b/pdns/Makefile.am @@ -21,7 +21,7 @@ bin_PROGRAMS = pdns_control pdnssec dnsreplay endif EXTRA_PROGRAMS=pdns_recursor sdig tsig-tests speedtest pdns_control dnsscope dnsgram \ - dnsdemog dnswasher dnsscan dnslog nproxy notify pdnssec dnsbulktest # tcptorture +toysdig dnsdemog dnswasher dnsscan dnslog nproxy notify pdnssec dnsbulktest # dnslabel # tcptorture pdns_server_SOURCES=dnspacket.cc nameserver.cc tcpreceiver.hh \ qtype.cc logger.cc arguments.cc packethandler.cc tcpreceiver.cc \ @@ -43,7 +43,7 @@ base64.hh zoneparser-tng.cc dnsrecords.cc dnswriter.cc \ rcpgenerator.cc dnsparser.cc dns_random.hh aes/aescpp.h \ aes/aescrypt.c aes/aes.h aes/aeskey.c aes/aes_modes.c aes/aesopt.h \ aes/aestab.c aes/aestab.h aes/brg_endian.h aes/brg_types.h aes/dns_random.cc \ -randomhelper.cc namespaces.hh nsecrecords.cc base32.cc dnsseckeeper.cc dnssecinfra.cc \ +randomhelper.cc namespaces.hh nsecrecords.cc base32.cc fsdnsseckeeper.cc dnssecinfra.cc \ dnsseckeeper.hh dnssecinfra.hh base32.hh # @@ -52,7 +52,7 @@ pdns_server_LDADD=$(BOOST_FILESYSTEM_LIBS) $(BOOST_SYSTEM_LIBS) -lpolarssl -pdnssec_SOURCES=pdnssec.cc dnsseckeeper.cc sstuff.hh dnsparser.cc dnsparser.hh dnsrecords.cc dnswriter.cc dnswriter.hh \ +pdnssec_SOURCES=pdnssec.cc fsdnsseckeeper.cc sstuff.hh dnsparser.cc dnsparser.hh dnsrecords.cc dnswriter.cc dnswriter.hh \ misc.cc misc.hh rcpgenerator.cc rcpgenerator.hh base64.cc base64.hh unix_utility.cc \ logger.cc statbag.cc qtype.cc sillyrecords.cc nsecrecords.cc dnssecinfra.cc dnssecinfra.hh \ base32.cc ueberbackend.cc dnsbackend.cc arguments.cc packetcache.cc dnspacket.cc \ @@ -69,6 +69,11 @@ sdig_SOURCES=sdig.cc sstuff.hh dnsparser.cc dnsparser.hh dnsrecords.cc dnswriter misc.cc misc.hh rcpgenerator.cc rcpgenerator.hh base64.cc base64.hh unix_utility.cc \ logger.cc statbag.cc qtype.cc sillyrecords.cc nsecrecords.cc base32.cc +toysdig_SOURCES=toysdig.cc sstuff.hh dnsparser.cc dnsparser.hh dnsrecords.cc dnswriter.cc dnswriter.hh \ + misc.cc misc.hh rcpgenerator.cc rcpgenerator.hh base64.cc base64.hh unix_utility.cc \ + logger.cc statbag.cc qtype.cc sillyrecords.cc nsecrecords.cc base32.cc dnslabel.cc dnslabel.hh + + #tcptorture_SOURCES=tcptorture.cc sstuff.hh dnsparser.cc dnsparser.hh dnsrecords.cc dnswriter.cc dnswriter.hh \ # misc.cc misc.hh rcpgenerator.cc rcpgenerator.hh base64.cc base64.hh unix_utility.cc \ # logger.cc statbag.cc qtype.cc sillyrecords.cc nsecrecords.cc base32.cc diff --git a/pdns/dnssecinfra.cc b/pdns/dnssecinfra.cc index 3fb90925b..f664cecd5 100644 --- a/pdns/dnssecinfra.cc +++ b/pdns/dnssecinfra.cc @@ -186,7 +186,7 @@ bool getSignerFor(const std::string& keyRepositoryDir, const std::string& qname, signer=qname; do { - if(dk.haveKSKFor(signer)) + if(dk.haveActiveKSKFor(signer)) return true; } while(chopOff(signer)); return false; @@ -211,8 +211,8 @@ DNSKEYRecordContent getDNSKEYFor(const std::string& keyRepositoryDir, const std: DNSSECPrivateKey dpk; if(!withKSK) { - DNSSECKeeper::zskset_t zskset=dk.getZSKsFor(qname); - BOOST_FOREACH(DNSSECKeeper::zskset_t::value_type value, zskset) { + DNSSECKeeper::keyset_t zskset=dk.getKeys(qname, false); + BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value, zskset) { if(value.second.active) { cerr<<"Found a ZSK for '"< -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include // for 'operator+=()' -#include -using namespace boost::assign; -namespace fs = boost::filesystem; - -using namespace std; -using namespace boost; - -void RSAContext::create(unsigned int bits) -{ - havege_state hs; - havege_init( &hs ); - - rsa_init(&d_context, RSA_PKCS_V15, 0, havege_rand, &hs ); // FIXME this leaks memory - int ret=rsa_gen_key(&d_context, bits, 65537); - if(ret < 0) - throw runtime_error("Key generation failed"); -} - -std::string RSAContext::convertToISC() -{ - string ret; - typedef vector > outputs_t; - outputs_t outputs; - push_back(outputs)("Modulus", &d_context.N)("PublicExponent",&d_context.E) - ("Modulus", &d_context.N) - ("PublicExponent",&d_context.E) - ("PrivateExponent",&d_context.D) - ("Prime1",&d_context.P) - ("Prime2",&d_context.Q) - ("Exponent1",&d_context.DP) - ("Exponent2",&d_context.DQ) - ("Coefficient",&d_context.QP); - - ret = "Private-key-format: v1.2\nAlgorithm: 5 (RSASHA1)\n"; - - BOOST_FOREACH(outputs_t::value_type value, outputs) { - ret += value.first; - ret += ": "; - unsigned char tmp[mpi_size(value.second)]; - mpi_write_binary(value.second, tmp, sizeof(tmp)); - unsigned char base64tmp[sizeof(tmp)*2]; - int dlen=sizeof(base64tmp); - base64_encode(base64tmp, &dlen, tmp, sizeof(tmp)); - ret.append((const char*)base64tmp, dlen); - ret.append(1, '\n'); - } - return ret; -} - -bool DNSSECKeeper::haveKSKFor(const std::string& zone, DNSSECPrivateKey* dpk) -{ - fs::path full_path = fs::system_complete( fs::path(d_dirname + "/" + zone + "/ksks/" ) ); - - if ( !fs::exists( full_path ) ) - return false; - - fs::directory_iterator end_iter; - for ( fs::directory_iterator dir_itr( full_path ); - dir_itr != end_iter; - ++dir_itr ) - { - // cerr<<"Entry: '"<< dir_itr->leaf() <<"'"<leaf(),".isc")) { - // cerr<<"Hit!"<d_key.getContext(), dir_itr->path().file_string().c_str()); - - if(getNSEC3PARAM(zone)) { - dpk->d_algorithm = 7; - } - else { - dpk->d_algorithm = 5; - } - - } - return true; - } - } - - return false; -} - -unsigned int DNSSECKeeper::getNextKeyIDFromDir(const std::string& dirname) -{ - fs::path full_path = fs::system_complete( fs::path(dirname)); - - if ( !fs::exists( full_path ) ) - unixDie("Unable to get next free key id from '"+dirname+"'"); - - fs::directory_iterator end_iter; - unsigned int maxID=0; - for ( fs::directory_iterator dir_itr( full_path ); - dir_itr != end_iter; - ++dir_itr ) - { - if(ends_with(dir_itr->leaf(),".isc")) { - maxID = max(maxID, (unsigned int)atoi(dir_itr->leaf().c_str())); - } - } - return maxID+1; -} - -void DNSSECKeeper::addZSKFor(const std::string& name, int algorithm, bool active) -{ - DNSSECPrivateKey dpk; - dpk.d_key.create(1024); // for testing, 1024 - - string isc = dpk.d_key.convertToISC(); - DNSKEYRecordContent drc = dpk.getDNSKEY(); - drc.d_flags = 256; // KSK - drc.d_algorithm = algorithm; - string iscName=d_dirname+"/"+name+"/zsks/"; - unsigned int id = getNextKeyIDFromDir(iscName); - time_t inception=time(0); - - struct tm ts; - gmtime_r(&inception, &ts); - - iscName += (boost::format("%06d-%04d%02d%02d%02d%02d") % id - % (1900+ts.tm_year) % (ts.tm_mon + 1) - % ts.tm_mday % ts.tm_hour % ts.tm_min).str(); - - iscName += active ? ".active" : ".passive"; - - { - ofstream iscFile((iscName+".isc").c_str()); - iscFile << isc; - } - - { - ofstream dnskeyFile((iscName+".dnskey").c_str()); - dnskeyFile << toCanonic("", name) << " IN DNSKEY " << drc.getZoneRepresentation()<(DNSRecordContent::mastermake(QType::NSEC3PARAM, 1, descr)); - if(!tmp) { - cerr<<"Could not parse "<< full_path.external_directory_string() <d_salt)<getZoneRepresentation(); - - - ofstream of(full_path.external_directory_string().c_str()); - of << descr; - } - else { - unlink(full_path.external_directory_string().c_str()); - } -} - - -DNSSECKeeper::zskset_t DNSSECKeeper::getZSKsFor(const std::string& zone, bool all) -{ - zskset_t zskset; - - fs::path full_path = fs::system_complete( fs::path(d_dirname + "/" + zone + "/zsks/" ) ); - - if ( !fs::exists( full_path ) ) - return zskset; - - fs::directory_iterator end_iter; - for ( fs::directory_iterator dir_itr( full_path ); - dir_itr != end_iter; - ++dir_itr ) - { - // cerr<<"Entry: '"<< dir_itr->leaf() <<"'"<leaf(),".isc")) { - //cerr<<"Hit!"<path().file_string().c_str()); - - if(getNSEC3PARAM(zone)) { - dpk.d_algorithm = 7; - } - else { - dpk.d_algorithm = 5; - } - - struct tm ts1, ts2; - - memset(&ts1, 0, sizeof(ts1)); - memset(&ts2, 0, sizeof(ts2)); - - unsigned int id; - sscanf(dir_itr->leaf().c_str(), "%06u-%04d%02d%02d%02d%02d", - &id, - &ts1.tm_year, - &ts1.tm_mon, &ts1.tm_mday, &ts1.tm_hour, &ts1.tm_min); - - - ts1.tm_year -= 1900; - - ts1.tm_mon--; - - KeyMetaData kmd; - - kmd.id = id; - kmd.fname = dir_itr->leaf(); - kmd.active = kmd.fname.find(".active") != string::npos; - zskset.push_back(make_pair(dpk, kmd)); - } - sort(zskset.begin(), zskset.end(), zskCompareByID); - } - - return zskset; -} - -DNSKEYRecordContent DNSSECPrivateKey::getDNSKEY() -{ - return makeDNSKEYFromRSAKey(&d_key.getContext(), d_algorithm); -} - - -void DNSSECKeeper::secureZone(const std::string& name, int algorithm) -{ - mkdir((d_dirname+"/"+name).c_str(), 0700); - mkdir((d_dirname+"/"+name+"/ksks").c_str(), 0700); - if(mkdir((d_dirname+"/"+name+"/zsks").c_str(), 0700) < 0) - unixDie("Making directory for keys in '"+d_dirname+"'"); - - // now add the KSK - - DNSSECPrivateKey dpk; - dpk.d_key.create(2048); // for testing, 1024 - - string isc = dpk.d_key.convertToISC(); - DNSKEYRecordContent drc = dpk.getDNSKEY(); - drc.d_flags = 257; // ZSK (?? for a KSK?) - drc.d_algorithm = algorithm; - string iscName=d_dirname+"/"+name+"/ksks/"; - - time_t now=time(0); - struct tm ts; - gmtime_r(&now, &ts); - unsigned int id=1; - iscName += (boost::format("%06d-%04d%02d%02d%02d%02d.%u") % id - % (1900+ts.tm_year) % (ts.tm_mon + 1) - % ts.tm_mday % ts.tm_hour % ts.tm_min % drc.getTag()).str(); - - - { - ofstream iscFile((iscName+".isc").c_str()); - iscFile << isc; - } - - { - ofstream dnskeyFile((iscName+".dnskey").c_str()); - dnskeyFile << toCanonic("", name) << " IN DNSKEY " << drc.getZoneRepresentation()< #include #include +#include #include "dnsrecords.hh" #define PDNSSEC_MI(x) mpi_init(&d_context.x, 0) @@ -66,6 +67,7 @@ private: rsa_context d_context; }; +// ? #undef PDNSSEC_MC #undef PDNSSEC_MI #undef PDNSSEC_MF @@ -84,27 +86,30 @@ class DNSSECKeeper public: struct KeyMetaData { - unsigned int id; + unsigned int id; bool active; + bool keyOrZone; string fname; }; - typedef std::vector > zskset_t; + typedef std::vector > keyset_t; public: explicit DNSSECKeeper(const std::string& dirname) : d_dirname(dirname){} - bool haveKSKFor(const std::string& zone, DNSSECPrivateKey* ksk=0); + bool haveActiveKSKFor(const std::string& zone, DNSSECPrivateKey* ksk=0); - zskset_t getZSKsFor(const std::string& zone, bool all=false); - void addZSKFor(const std::string& zname, int algorithm, bool next=false); - - void deleteZSKFor(const std::string& zname, const std::string& fname); + keyset_t getKeys(const std::string& zone, boost::tribool allOrKeyOrZone = boost::indeterminate); + void addKey(const std::string& zname, bool keyOrZone, int algorithm, bool active=true); + void removeKey(const std::string& zname, unsigned int id); + void activateKey(const std::string& zname, unsigned int id); + void deactivateKey(const std::string& zname, unsigned int id); void secureZone(const std::string& fname, int algorithm); bool getNSEC3PARAM(const std::string& zname, NSEC3PARAMRecordContent* n3p=0); void setNSEC3PARAM(const std::string& zname, const NSEC3PARAMRecordContent* n3p); static unsigned int getNextKeyIDFromDir(const std::string& dirname); + std::string getKeyFilenameById(const std::string& dirname, unsigned int id); private: std::string d_dirname; }; diff --git a/pdns/pdnssec.cc b/pdns/pdnssec.cc index e7b1de00c..321243b2e 100644 --- a/pdns/pdnssec.cc +++ b/pdns/pdnssec.cc @@ -189,7 +189,7 @@ try cmds = g_vm["commands"].as >(); if(cmds.empty() || g_vm.count("help")) { - cerr<<"Usage: \npdnssec [options] [show-zone] [secure-zone] [alter-zone] [order-zone] [update-zone-keys]\n"; + cerr<<"Usage: \npdnssec [options] [show-zone] [secure-zone] [alter-zone] [order-zone] [add-zone-key] [deactivate-zone-key] [remove-zone-key] [activate-zone-key]\n"; cerr< -#include -#include -#include -#include "dnssecinfra.hh" -#include "base32.hh" - StatBag S; -MOADNSParser* askQuestion(DNSPacketWriter&, vector& packet, const char* remote, uint16_t port=53) -{ - int sock=socket(AF_INET, SOCK_DGRAM, 0); - - if(sock < 0) - unixDie("Creating SCTP socket"); - - ComboAddress dest(remote + (*remote=='@'), port); - struct msghdr msg; - struct iovec iomsg; - - msg.msg_name=&dest; - msg.msg_namelen=dest.getSocklen(); - msg.msg_iov=&iomsg; - iomsg.iov_base=&*packet.begin(); - iomsg.iov_len=packet.size(); - msg.msg_iovlen=1; - msg.msg_control=0; - msg.msg_controllen=0; - msg.msg_flags=0; // just to be sure - - sendmsg(sock, &msg, 0); - - char replybuf[4096]; - socklen_t destlen=dest.getSocklen(); - int len=recvfrom(sock, replybuf, sizeof(replybuf), 0, (struct sockaddr*)&dest, &destlen); - if(len < 0) - unixDie("recvfrom on sctp"); - - string reply(replybuf, len); - - return new MOADNSParser(reply); -} - -void getKeys(const std::string& qname, uint16_t tag); - -void doVerifySignature(const std::string& qname, map > >& dkrcs, pair >, vector > >& records) -{ - rsa_context rsa; - - BOOST_FOREACH(shared_ptr& rrc, records.second) { - cerr<<"\nVerifying "<d_type)<<"\n"; - - cerr<<"Signer is: "<d_signer<<" for which we have "<d_signer].size()<<" DNSKEYs, want the one with"; - cerr<<" tag: "<d_tag<d_signer, rrc->d_tag); - - if(dkrcs[rrc->d_signer].empty()) { - cerr<<"\tNo keys!\n"; - return; - } - - vector >& signRecords= records.first; - - string hash=getSHA1HashForRRSET(qname, *rrc.get(), signRecords); - int ret; - int success=0; - BOOST_FOREACH(shared_ptr dkrc, dkrcs[rrc->d_signer]) { - if(dkrc->getTag() != rrc->d_tag) { - cerr<<"Skipping key with wrong tag "<getTag()<< " != needed "<d_tag<d_signature.c_str() ) ) != 0) { - fprintf(stderr, "Verification with tag %d failed with error %d\n", dkrc->getTag(), ret); - } - else { - fprintf(stderr, "DNSSEC Record verified Ok with tag %d!\n", dkrc->getTag()); - success++; - break; - } - } - if(success) - cerr<<"\t at least one verification was succesful!\n"; - } -} - -typedef map > > dkrc_t; -dkrc_t dkrc; - -void getKeys(const std::string& qname, uint16_t tag) -{ - BOOST_FOREACH(shared_ptr& drc, dkrc[qname]) { - if(drc->getTag() == tag) - return; - } - - vector packet; - - DNSPacketWriter pw(packet, qname, QType::DNSKEY); - - pw.getHeader()->id=1234; - pw.getHeader()->rd=1; - - pw.addOpt(4000, 0, EDNSOpts::DNSSECOK); // int udpsize, int extRCode, int Z - pw.commit(); - - MOADNSParser* mdp=askQuestion(pw, packet, "199.249.112.1", 53); - if(mdp->d_header.tc) { - cerr<<"Truncated!\n"; - } - for(MOADNSParser::answers_t::const_iterator i=mdp->d_answers.begin(); i!=mdp->d_answers.end(); ++i) { - if(i->first.d_type==QType::DNSKEY) { - shared_ptr dkrcptr=dynamic_pointer_cast(i->first.d_content); - dkrc[i->first.d_label].push_back(dkrcptr); - cerr<<"Added DNSKEY for '"< packet; - DNSPacketWriter pw(packet, argv[1], DNSRecordContent::TypeToNumber(argv[2])); + DNSPacketWriter pw(packet, argv[3], DNSRecordContent::TypeToNumber(argv[4])); - pw.getHeader()->id=1234; - pw.getHeader()->rd=0; + pw.getHeader()->rd=1; + + Socket sock(InterNetwork, Datagram); + ComboAddress dest(argv[1] + (*argv[1]=='@'), atoi(argv[2])); + sock.sendTo(string((char*)&*packet.begin(), (char*)&*packet.end()), dest); + + string reply; + sock.recvFrom(reply, dest); - pw.addOpt(4000, 0, EDNSOpts::DNSSECOK); // int udpsize, int extRCode, int Z - pw.commit(); + MOADNSParser mdp(reply); + cout<<"Reply to question for qname='"<4 ? atoi(argv[4]) : 53); - if(mdp->d_header.tc) { - cerr<<"Truncated!\n"; - } - - typedef map< pair, - pair >, vector > - > > grouped_t; - grouped_t grouped; - - string salt; - int iterations; - for(MOADNSParser::answers_t::const_iterator i=mdp->d_answers.begin(); i!=mdp->d_answers.end(); ++i) { + for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) { cout<first.d_place-1<<"\t"<first.d_label<<"\tIN\t"<first.d_type); cout<<"\t"<first.d_ttl<<"\t"<< i->first.d_content->getZoneRepresentation()<<"\n"; - - if(i->first.d_type==QType::DNSKEY) { - dkrc[i->first.d_label].push_back(dynamic_pointer_cast(i->first.d_content)); - } - - if(i->first.d_type==QType::NSEC3) { - salt=dynamic_pointer_cast(i->first.d_content)->d_salt; - iterations=dynamic_pointer_cast(i->first.d_content)->d_iterations; - } - - - if(i->first.d_type!=QType::RRSIG) - grouped[make_pair(i->first.d_label, i->first.d_type)].first.push_back(i->first.d_content); - else { - shared_ptr rrc=dynamic_pointer_cast(i->first.d_content); - grouped[make_pair(i->first.d_label, rrc->d_type)].second.push_back(rrc); - cerr<<"Algorithm = "<<(int)rrc->d_algorithm<& content, value.second) { - DSRecordContent dsrc = makeDSFromDNSKey(value.first, *content.get()); - cerr<<"ds: "<