From: Bert Hubert Date: Sun, 9 Jan 2011 08:58:55 +0000 (+0000) Subject: * Make everything aware of multiple simultaneous signing keys X-Git-Tag: auth-3.0~404 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ade1b1e98a7e3833c2795bcf8e5e09d09360a0a0;p=pdns * Make everything aware of multiple simultaneous signing keys * Remove APIs that contravene this * Rename SHA1-centric functioncalls: s/SHA1/Hash/g * Diagnose the sillines of getSignerApexFor which rediscovers the right key to use.. * no fix yet * If no ZSKs, use active KSKs for signing (allowing single-key operation) * Fix up signature caching which assumed keytag = key identity * Only sign the DNSKEY RRSET with active KSKs from now on * Make secure-zone run rectify-zone * Remove --force from secure-zone (silly) * Make RSASHA256 default for secure-zone git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@1843 d19b8d6e-7fed-0310-83ef-9ca221ded41b --- diff --git a/pdns/dbdnsseckeeper.cc b/pdns/dbdnsseckeeper.cc index 904847e4e..609c362b0 100644 --- a/pdns/dbdnsseckeeper.cc +++ b/pdns/dbdnsseckeeper.cc @@ -19,15 +19,17 @@ namespace fs = boost::filesystem; using namespace std; using namespace boost; -bool DNSSECKeeper::haveActiveKSKFor(const std::string& zone, DNSSECPrivateKey* dpk) +bool DNSSECKeeper::haveActiveKSKFor(const std::string& zone) { keyset_t keys = getKeys(zone, true); // need to get an *active* one! //cerr<<__FUNCTION__<<"Got "<first; + BOOST_FOREACH(keyset_t::value_type& val, keys) { + if(val.second.active) { + return true; + } } - return !keys.empty(); + return false; } @@ -179,133 +181,126 @@ void DNSSECKeeper::secureZone(const std::string& name, int algorithm) { addKey(name, true, algorithm); } - -bool getSignerFor(DNSSECKeeper& dk, const std::string& qname, std::string &signer, uint8_t& algorithm) + +// nobody should ever call this function, you know the SOA/auth already! +bool getSignerApexFor(DNSSECKeeper& dk, const std::string& qname, std::string &signer) { + // cerr<<"getSignerApexFor: called, and should not be, should go away!"< >& toSign, RRSIGRecordContent& rrc, bool ksk) +/* this is where the RRSIG gets filled out, the hashing gets done, key apex *name* gets found, + but the actual signing happens in fillOutRRSIG */ +int getRRSIGsForRRSET(DNSSECKeeper& dk, const std::string signQName, uint16_t signQType, uint32_t signTTL, + vector >& toSign, vector& rrcs, bool ksk) { if(toSign.empty()) return -1; - + RRSIGRecordContent rrc; rrc.d_type=signQType; - // d_algorithm gets filled out by fillOutRRSIG, since it gets the key + // d_algorithm gets filled out by getSignerAPEX, since only it looks up the key rrc.d_labels=countLabels(signQName); rrc.d_originalttl=signTTL; rrc.d_siginception=getCurrentInception();; rrc.d_sigexpire = rrc.d_siginception + 14*86400; // XXX should come from zone metadata + rrc.d_tag = 0; - rrc.d_tag=0; - if(!getSignerFor(dk, signQName, rrc.d_signer, rrc.d_algorithm)) { + // XXX we know the apex already.. is is the SOA name which we determined earlier + if(!getSignerApexFor(dk, signQName, rrc.d_signer)) { cerr<<"No signer known for '"< KSKs, ZSKs; + vector* signingKeys; + + // if ksk==1, only get KSKs + // if ksk==0, get ZSKs, unless there is no ZSK, then get KSK + BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type& keymeta, keys) { + if(!keymeta.second.active) + continue; + + if(keymeta.second.keyOrZone) + KSKs.push_back(keymeta.first); + else if(!ksk) + ZSKs.push_back(keymeta.first); + } + if(ksk) + signingKeys = &KSKs; + else { + if(ZSKs.empty()) + signingKeys = &KSKs; + else + signingKeys =&ZSKs; + } + + BOOST_FOREACH(DNSSECPrivateKey& dpk, *signingKeys) { + fillOutRRSIG(dpk, signQName, rrc, toSign); + rrcs.push_back(rrc); + } return 0; } +// this is the entrypoint from DNSPacket void addSignature(DNSSECKeeper& dk, const std::string signQName, const std::string& wildcardname, uint16_t signQType, uint32_t signTTL, DNSPacketWriter::Place signPlace, vector >& toSign, uint16_t maxReplyLen, DNSPacketWriter& pw) { // cerr<<"Asked to sign '"< rrcs; if(toSign.empty()) return; - for(int ksk = 0; ksk < 2; ++ksk) { - if(getRRSIGForRRSET(dk, wildcardname.empty() ? signQName : wildcardname, signQType, signTTL, toSign, rrc, ksk) < 0) { - cerr<<"Error signing a record!"< maxReplyLen) { pw.rollback(); pw.getHeader()->tc=1; return; } - - pw.commit(); - if(signQType != QType::DNSKEY) - break; } + pw.commit(); toSign.clear(); } -pthread_mutex_t g_rrsigs_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t g_signatures_lock = PTHREAD_MUTEX_INITIALIZER; +static map, string> g_signatures; -map, RRSIGRecordContent> g_rrsigs; - -void fillOutRRSIG(DNSSECKeeper& dk, const std::string& signQName, RRSIGRecordContent& rrc, const std::string& hash, vector >& toSign, bool withKSK) +void fillOutRRSIG(DNSSECPrivateKey& dpk, const std::string& signQName, RRSIGRecordContent& rrc, vector >& toSign) { - RSAContext rc; - - DNSKEYRecordContent drc=getDNSKEYFor(dk, rrc.d_signer, withKSK, &rc); + DNSKEYRecordContent drc= dpk.getDNSKEY(); + RSAContext& rc = dpk.d_key; rrc.d_tag = drc.getTag(); rrc.d_algorithm = drc.d_algorithm; + string realhash=getHashForRRSET(signQName, rrc, toSign); // this is what we sign - { - Lock l(&g_rrsigs_lock); - if(g_rrsigs.count(make_pair(hash, rrc.d_tag))) { - // cerr<<"RRSIG cache hit !"<& a, const shared_ptr return a->serialize("", true, true) < b->serialize("", true, true); } -string getSHA1HashForRRSET(const std::string& qname, const RRSIGRecordContent& rrc, vector >& signRecords) +string getHashForRRSET(const std::string& qname, const RRSIGRecordContent& rrc, vector >& signRecords) { sort(signRecords.begin(), signRecords.end(), sharedDNSSECCompare); string toHash; toHash.append(const_cast(rrc).serialize("", true, true)); - toHash.resize(toHash.size() - rrc.d_signature.length()); // chop off the end; - // cerr<<"toHash start size: "<& add, signRecords) { - // cerr<<"\t IN "<getZoneRepresentation()<<"\n"; toHash.append(toLower(simpleCompress(qname, ""))); uint16_t tmp=htons(rrc.d_type); toHash.append((char*)&tmp, 2); @@ -248,7 +245,6 @@ string getSHA1HashForRRSET(const std::string& qname, const RRSIGRecordContent& r toHash.append((char*)&tmp, 2); toHash.append(rdata); } - // cerr<<"toHash: "<& a, const shared_ptr& b); -string getSHA1HashForRRSET(const std::string& qname, const RRSIGRecordContent& rrc, std::vector >& signRecords); +string getHashForRRSET(const std::string& qname, const RRSIGRecordContent& rrc, std::vector >& signRecords); DNSKEYRecordContent makeDNSKEYFromRSAKey(const rsa_context* rc, uint8_t algorithm, uint16_t flags); DSRecordContent makeDSFromDNSKey(const std::string& qname, const DNSKEYRecordContent& drc, int digest=1); @@ -36,15 +36,15 @@ int countLabels(const std::string& signQName); class RSAContext; class DNSSECKeeper; +struct DNSSECPrivateKey; -bool getSignerFor(DNSSECKeeper& dk, const std::string& keyrepodir, const std::string& qname, std::string &signer, uint8_t& algorithm); -DNSKEYRecordContent getDNSKEYFor(DNSSECKeeper& dk, const std::string& keyrepodir, const std::string& qname, bool withKSK, RSAContext* rc); -void fillOutRRSIG(DNSSECKeeper& dk, const std::string& signQName, RRSIGRecordContent& rrc, const std::string& hash, vector >& toSign, bool withKSK=false); +bool getSignerApexFor(DNSSECKeeper& dk, const std::string& keyrepodir, const std::string& qname, std::string &signer); +void fillOutRRSIG(DNSSECPrivateKey& dpk, const std::string& signQName, RRSIGRecordContent& rrc, vector >& toSign); uint32_t getCurrentInception(); void addSignature(DNSSECKeeper& dk, const std::string signQName, const std::string& wildcardname, uint16_t signQType, uint32_t signTTL, DNSPacketWriter::Place signPlace, vector >& toSign, uint16_t maxReplyLength, DNSPacketWriter& pw); -int getRRSIGForRRSET(DNSSECKeeper& dk, const std::string signQName, uint16_t signQType, uint32_t signTTL, - vector >& toSign, RRSIGRecordContent &rrc, bool ksk); +int getRRSIGsForRRSET(DNSSECKeeper& dk, const std::string signQName, uint16_t signQType, uint32_t signTTL, + vector >& toSign, vector &rrc, bool ksk); std::string hashQNameWithSalt(unsigned int times, const std::string& salt, const std::string& qname); diff --git a/pdns/dnsseckeeper.hh b/pdns/dnsseckeeper.hh index 1d117e662..ad99fe3ec 100644 --- a/pdns/dnsseckeeper.hh +++ b/pdns/dnsseckeeper.hh @@ -12,6 +12,11 @@ #define PDNSSEC_MC(x) PDNSSEC_MI(x); mpi_copy(&d_context.x, const_cast(&orig.d_context.x)) #define PDNSSEC_MF(x) mpi_free(&d_context.x, 0) +inline bool operator<(const mpi& a, const mpi& b) +{ + return mpi_cmp_mpi(&a, &b) < 0; +} + class RSAContext { public: @@ -28,6 +33,12 @@ public: PDNSSEC_MF(E); PDNSSEC_MF(D); PDNSSEC_MF(P); PDNSSEC_MF(Q); PDNSSEC_MF(DP); PDNSSEC_MF(DQ); PDNSSEC_MF(QP); PDNSSEC_MF(RN); PDNSSEC_MF(RP); PDNSSEC_MF(RQ); } + bool operator<(const RSAContext& rhs) const + { + return tie(d_context.N, d_context.E, d_context.D, d_context.P, d_context.Q, d_context.DP, d_context.DQ, d_context.QP) + < tie(rhs.d_context.N, rhs.d_context.E, rhs.d_context.D, rhs.d_context.P, rhs.d_context.Q, rhs.d_context.DP, rhs.d_context.DQ, rhs.d_context.QP); + } + RSAContext(const RSAContext& orig) { d_context.ver = orig.d_context.ver; @@ -74,7 +85,7 @@ private: rsa_context d_context; }; -// ? +// see above #undef PDNSSEC_MC #undef PDNSSEC_MI #undef PDNSSEC_MF @@ -104,7 +115,7 @@ private: UeberBackend d_db; public: DNSSECKeeper() : d_db("key-only"){} - bool haveActiveKSKFor(const std::string& zone, DNSSECPrivateKey* ksk=0); + bool haveActiveKSKFor(const std::string& zone); keyset_t getKeys(const std::string& zone, boost::tribool allOrKeyOrZone = boost::indeterminate); DNSSECPrivateKey getKeyById(const std::string& zone, unsigned int id); diff --git a/pdns/packethandler.cc b/pdns/packethandler.cc index 4a7c7dff0..915a67def 100644 --- a/pdns/packethandler.cc +++ b/pdns/packethandler.cc @@ -207,23 +207,13 @@ int PacketHandler::doDNSKEYRequest(DNSPacket *p, DNSPacket *r) bool haveOne=false; DNSSECPrivateKey dpk; - if(d_dk.haveActiveKSKFor(p->qdomain, &dpk)) { - rr.qtype=QType::DNSKEY; - rr.ttl=3600; - rr.qname=p->qdomain; - rr.content=dpk.getDNSKEY().getZoneRepresentation(); - rr.auth = true; - r->addRecord(rr); - haveOne=true; - } - - DNSSECKeeper::keyset_t zskset = d_dk.getKeys(p->qdomain, false); - BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value, zskset) { + DNSSECKeeper::keyset_t keyset = d_dk.getKeys(p->qdomain); + BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value, keyset) { rr.qtype=QType::DNSKEY; rr.ttl=3600; rr.qname=p->qdomain; rr.content=value.first.getDNSKEY().getZoneRepresentation(); - + rr.auth=true; r->addRecord(rr); haveOne=true; } @@ -935,7 +925,7 @@ DNSPacket *PacketHandler::question(DNSPacket *p) void PacketHandler::synthesiseRRSIGs(DNSPacket* p, DNSPacket* r) { - cerr<<"Need to fake up the RRSIGs some way.."<qdomain, p); DNSResourceRecord rr; @@ -996,13 +986,12 @@ void PacketHandler::synthesiseRRSIGs(DNSPacket* p, DNSPacket* r) rr.qtype = QType::RRSIG; BOOST_FOREACH(records_t::value_type& iter, records) { - RRSIGRecordContent rrc; - for(int ksk =0 ; ksk < 2; ++ksk) { - getRRSIGForRRSET(d_dk, p->qdomain, iter.first, 3600, iter.second, rrc, ksk); + vector rrcs; + + getRRSIGsForRRSET(d_dk, p->qdomain, iter.first, 3600, iter.second, rrcs, iter.first == QType::DNSKEY); + BOOST_FOREACH(RRSIGRecordContent& rrc, rrcs) { rr.content=rrc.getZoneRepresentation(); r->addRecord(rr); - if(iter.first != QType::DNSKEY) - break; } } } diff --git a/pdns/pdnssec.cc b/pdns/pdnssec.cc index 354dd35be..0a1faf42b 100644 --- a/pdns/pdnssec.cc +++ b/pdns/pdnssec.cc @@ -174,6 +174,35 @@ void checkZone(DNSSECKeeper& dk, const std::string& zone) cerr<<"Checked "< 2 ? cmds[2] : "1 0 1 ab";