From: Bert Hubert Date: Mon, 27 Dec 2010 15:57:14 +0000 (+0000) Subject: this implies that there will be more dnsseckeepers - database backed for example X-Git-Tag: auth-3.0~489 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7125a49a3d7497178ccf337de5ed030ebf612f18;p=pdns this implies that there will be more dnsseckeepers - database backed for example git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@1758 d19b8d6e-7fed-0310-83ef-9ca221ded41b --- diff --git a/pdns/fsdnsseckeeper.cc b/pdns/fsdnsseckeeper.cc new file mode 100644 index 000000000..2a86f3bc4 --- /dev/null +++ b/pdns/fsdnsseckeeper.cc @@ -0,0 +1,356 @@ +#include "dnsseckeeper.hh" +#include "dnssecinfra.hh" +#include "statbag.hh" +#include +#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::haveActiveKSKFor(const std::string& zone, DNSSECPrivateKey* dpk) +{ + keyset_t keys = getKeys(zone, true); + // need to get an *active* one! + if(dpk && !keys.empty()) { + *dpk = keys.begin()->first; + } + return !keys.empty(); + + #if 0 + fs::path full_path = fs::system_complete( fs::path(d_dirname + "/" + zone + "/keys/" ) ); + + 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; + #endif +} + +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; +} + +std::string DNSSECKeeper::getKeyFilenameById(const std::string& dirname, unsigned int id) +{ + fs::path full_path = fs::system_complete( fs::path(dirname)); + + if ( !fs::exists( full_path ) ) + unixDie("Unable to get free key id from '"+dirname+"'"); + + fs::directory_iterator end_iter; + pair parts; + for ( fs::directory_iterator dir_itr( full_path ); + dir_itr != end_iter; + ++dir_itr ) + { + parts = splitField(dir_itr->leaf(), '-'); + if(atoi(parts.first.c_str()) == (signed int)id) + return dirname+"/"+dir_itr->leaf(); + } + throw runtime_error("Could not get filename for key id '"+lexical_cast(id)+"'"); +} + + +void DNSSECKeeper::addKey(const std::string& name, bool keyOrZone, 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+"/keys/"; + 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.%u") % id + % (1900+ts.tm_year) % (ts.tm_mon + 1) + % ts.tm_mday % ts.tm_hour % ts.tm_min % drc.getTag()).str(); + + iscName += keyOrZone ? ".ksk" : ".zsk"; + 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::keyset_t DNSSECKeeper::getKeys(const std::string& zone, boost::tribool allOrKeyOrZone) +{ + keyset_t keyset; + + fs::path full_path = fs::system_complete( fs::path(d_dirname + "/" + zone + "/keys/" ) ); + + if ( !fs::exists( full_path ) ) + return keyset; + + 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")) { + DNSSECPrivateKey dpk; + getRSAKeyFromISC(&dpk.d_key.getContext(), dir_itr->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; + kmd.keyOrZone = kmd.fname.find(".ksk") != string::npos; + if(boost::indeterminate(allOrKeyOrZone) || allOrKeyOrZone == kmd.keyOrZone) + keyset.push_back(make_pair(dpk, kmd)); + } + sort(keyset.begin(), keyset.end(), zskCompareByID); + } + + return keyset; +} + +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); + if(mkdir((d_dirname+"/"+name+"/keys").c_str(), 0700) < 0) + unixDie("Making directory for keys in '"+d_dirname+"'"); + + + // now add the KSK + + addKey(name, true, algorithm); +#if 0 + + 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+"/keys/"; + + 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.%s.%s") % id + % (1900+ts.tm_year) % (ts.tm_mon + 1) + % ts.tm_mday % ts.tm_hour % ts.tm_min % drc.getTag() % "ksk" % "active").str(); + + + { + ofstream iscFile((iscName+".isc").c_str()); + iscFile << isc; + } + + { + ofstream dnskeyFile((iscName+".dnskey").c_str()); + dnskeyFile << toCanonic("", name) << " IN DNSKEY " << drc.getZoneRepresentation()<