From 022e5e0b24c5f1741d0a38bf67bd3b5d60318f47 Mon Sep 17 00:00:00 2001 From: Bert Hubert Date: Tue, 25 Jan 2011 23:27:29 +0000 Subject: [PATCH] this huge commit adds support for RSASHA512 & draft-ietf-dnsext-ecdsa using the provisional codepoints, which may still change. ECDSAP256SHA256 and ECDSAP384SHA384 are supported.. iff you have Botan 1.9.x. Enable with ./configure --enable-botan19 GOST is just around the corner. Btw: don't run this commit in production pls - normal service will return tomorrow git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@1909 d19b8d6e-7fed-0310-83ef-9ca221ded41b --- configure.ac | 8 +- pdns/Makefile.am | 22 ++- pdns/botan19signers.cc | 169 +++++++++++++++++++ pdns/dbdnsseckeeper.cc | 21 ++- pdns/dnssecinfra.cc | 325 +++++++----------------------------- pdns/dnssecinfra.hh | 122 +++----------- pdns/pdnssec.cc | 10 +- pdns/polarrsakeyinfra.cc | 350 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 644 insertions(+), 383 deletions(-) create mode 100644 pdns/botan19signers.cc create mode 100644 pdns/polarrsakeyinfra.cc diff --git a/configure.ac b/configure.ac index af18545085..6aa4bcdef8 100644 --- a/configure.ac +++ b/configure.ac @@ -118,6 +118,13 @@ if test $enable_verbose_logging = yes; then AC_DEFINE(VERBOSELOG, 1, [If verbose fi AC_MSG_RESULT($enable_verbose_logging) +AC_MSG_CHECKING(whether we will be linking in Botan 1.9) +AC_ARG_ENABLE(botan1.9, + [ --enable-botan1.9 Use Botan 1.9],enable_botan19=yes, enable_botan19=no) +AC_MSG_RESULT($enable_botan19) +AM_CONDITIONAL(BOTAN19,test x"$enable_botan19" = "xyes") + + AC_MSG_CHECKING(whether we should build static binaries) AC_ARG_ENABLE(static-binaries, @@ -190,7 +197,6 @@ AC_ARG_ENABLE(recursor, enable_recursor=no ) AC_MSG_RESULT($enable_recursor) - AM_CONDITIONAL(RECURSOR,test x"$enable_recursor" = "xyes") for a in $modules $dynmodules diff --git a/pdns/Makefile.am b/pdns/Makefile.am index 2e5f0e1e72..b9331e6438 100644 --- a/pdns/Makefile.am +++ b/pdns/Makefile.am @@ -10,7 +10,7 @@ sysconf_DATA = pdns.conf-dist if RECURSOR sbin_PROGRAMS = pdns_server pdns_recursor -bin_PROGRAMS = pdns_control rec_control pdnssec dnsreplay +bin_PROGRAMS = pdns_control rec_control pdnssec dnsreplay else sbin_PROGRAMS = pdns_server bin_PROGRAMS = pdns_control pdnssec dnsreplay @@ -40,11 +40,16 @@ 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 dbdnsseckeeper.cc dnssecinfra.cc \ -dnsseckeeper.hh dnssecinfra.hh base32.hh dns.cc dnssecsigner.cc +dnsseckeeper.hh dnssecinfra.hh base32.hh dns.cc dnssecsigner.cc polarrsakeyinfra.cc # pdns_server_LDFLAGS=@moduleobjects@ @modulelibs@ @DYNLINKFLAGS@ @LIBDL@ @THREADFLAGS@ $(BOOST_FILESYSTEM_LDFLAGS) -Lext/polarssl/library pdns_server_LDADD=$(BOOST_FILESYSTEM_LIBS) -lpolarssl + +if BOTAN19 +pdns_server_SOURCES += botan19signers.cc +pdns_server_LDADD += -lbotan -lgmp +endif pdnssec_SOURCES=pdnssec.cc dbdnsseckeeper.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 \ @@ -54,11 +59,16 @@ pdnssec_SOURCES=pdnssec.cc dbdnsseckeeper.cc sstuff.hh dnsparser.cc dnsparser.hh backends/bind/bindparser.cc backends/bind/bindlexer.c \ backends/gsql/gsqlbackend.cc \ backends/gsql/gsqlbackend.hh backends/gsql/ssql.hh zoneparser-tng.cc \ - dynlistener.cc dns.cc randombackend.cc dnssecsigner.cc + dynlistener.cc dns.cc randombackend.cc dnssecsigner.cc polarrsakeyinfra.cc pdnssec_LDFLAGS=@moduleobjects@ @modulelibs@ @DYNLINKFLAGS@ @LIBDL@ @THREADFLAGS@ -Lext/polarssl/library/ pdnssec_LDADD=$(BOOST_FILESYSTEM_LIBS) $(BOOST_SYSTEM_LIBS) -lpolarssl $(BOOST_PROGRAM_OPTIONS_LIBS) +if BOTAN19 +pdnssec_SOURCES += botan19signers.cc +pdnssec_LDADD += -lbotan -lgmp +endif + sdig_SOURCES=sdig.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 @@ -117,14 +127,14 @@ dnsreplay_LDADD=$(BOOST_FILESYSTEM_LIBS) $(BOOST_PROGRAM_OPTIONS_LIBS) nproxy_SOURCES=nproxy.cc dnsparser.cc dnsrecords.cc dnsparser.hh \ rcpgenerator.cc rcpgenerator.hh base64.cc base64.hh dnswriter.cc dnswriter.hh \ - sillyrecords.cc selectmplexer.cc mplexer.hh + sillyrecords.cc selectmplexer.cc pollmplexer.cc mplexer.hh nproxy_LDFLAGS= @DYNLINKFLAGS@ @THREADFLAGS@ $(BOOST_FILESYSTEM_LDFLAGS) $(BOOST_PROGRAM_OPTIONS_LDFLAGS) nproxy_LDADD=$(BOOST_FILESYSTEM_LIBS) $(BOOST_PROGRAM_OPTIONS_LIBS) notify_SOURCES=notify.cc dnsparser.cc dnsrecords.cc dnsparser.hh \ rcpgenerator.cc rcpgenerator.hh base64.cc base64.hh dnswriter.cc dnswriter.hh \ - sillyrecords.cc selectmplexer.cc nsecrecords.cc base32.cc misc.cc unix_utility.cc \ + sillyrecords.cc selectmplexer.cc pollmplexer.cc nsecrecords.cc base32.cc misc.cc unix_utility.cc \ logger.cc qtype.cc statbag.cc notify_LDFLAGS= @DYNLINKFLAGS@ @THREADFLAGS@ $(BOOST_FILESYSTEM_LDFLAGS) $(BOOST_PROGRAM_OPTIONS_LDFLAGS) @@ -158,7 +168,7 @@ base64.cc base64.hh zoneparser-tng.cc zoneparser-tng.hh rec_channel.cc rec_chann rec_channel_rec.cc selectmplexer.cc epollmplexer.cc sillyrecords.cc htimer.cc htimer.hh \ aes/dns_random.cc aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c \ lua-pdns-recursor.cc lua-pdns-recursor.hh randomhelper.cc \ -recpacketcache.cc recpacketcache.hh dns.cc nsecrecords.cc base32.cc +recpacketcache.cc recpacketcache.hh dns.cc nsecrecords.cc base32.cc pollmplexer.cc #../modules/gmysqlbackend/smysql.cc diff --git a/pdns/botan19signers.cc b/pdns/botan19signers.cc new file mode 100644 index 0000000000..63084ed7a5 --- /dev/null +++ b/pdns/botan19signers.cc @@ -0,0 +1,169 @@ +#include +#include +#include +#include +#include "dnssecinfra.hh" + +using namespace Botan; + +class ECDSADNSPrivateKey : public DNSPrivateKey +{ +public: + void create(unsigned int bits); + std::string convertToISC(unsigned int algorithm) const; + std::string getPubKeyHash() const; + std::string sign(const std::string& hash) const; + bool verify(const std::string& hash, const std::string& signature) const; + std::string getPublicKeyString() const; + int getBits() const; + void fromISCString(DNSKEYRecordContent& drc, const std::string& content); + void fromPEMString(DNSKEYRecordContent& drc, const std::string& raw) + {} + + static DNSPrivateKey* maker(unsigned int algorithm) + { + return new ECDSADNSPrivateKey(); + } + +private: + static EC_Domain_Params getECParams(unsigned int algorithm); + shared_ptr d_key; +}; + +EC_Domain_Params ECDSADNSPrivateKey::getECParams(unsigned int algorithm) +{ + if(algorithm==13) + return EC_Domain_Params("1.2.840.10045.3.1.7"); + else if(algorithm == 14) + return EC_Domain_Params("1.3.132.0.34"); + else + throw runtime_error("Requested for unknown EC domain parameters for algorithm "+lexical_cast(algorithm)); +} + +void ECDSADNSPrivateKey::create(unsigned int bits) +{ + AutoSeeded_RNG rng; + EC_Domain_Params params; + if(bits==256) { + params = getECParams(13); + } + else if(bits == 384){ + params = getECParams(14); + } + else { + throw runtime_error("Unknown key length of "+lexical_cast(bits)+" bits requested from ECDSA class"); + } + d_key = shared_ptr(new ECDSA_PrivateKey(rng, params)); +} + +int ECDSADNSPrivateKey::getBits() const +{ + if(d_key->domain() == getECParams(13)) + return 256; + else if(d_key->domain() == getECParams(14)) + return 384; + else + return -1; +} + +std::string ECDSADNSPrivateKey::convertToISC(unsigned int algorithm) const +{ + /*Private-key-format: v1.2 + Algorithm: 13 (ECDSAP256SHA256) + PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ= */ + + ostringstream ret; + ret<<"Private-key-format: v1.2\nAlgorithm: "; + if(getBits()==256) + ret << "13 (ECDSAP256SHA256)\n"; + else if(getBits()==384) + ret << "14 (ECDSAP384SHA384)\n"; + else + ret <<" ? (?)\n"; + + ret<<"PrivateKey: "; + + const BigInt&x = d_key->private_value(); + SecureVector buffer=BigInt::encode(x); + + Pipe pipe(new Base64_Encoder); + pipe.process_msg(buffer); + ret<(new ECDSA_PrivateKey(params, bigint)); +} + +std::string ECDSADNSPrivateKey::getPubKeyHash() const +{ + const BigInt&x = d_key->private_value(); + SecureVector buffer=BigInt::encode(x); + return string((const char*)buffer.begin(), (const char*)buffer.end()); +} + +std::string ECDSADNSPrivateKey::getPublicKeyString() const +{ + const BigInt&x =d_key->public_point().get_affine_x(); + const BigInt&y =d_key->public_point().get_affine_y(); + + size_t part_size = std::max(x.bytes(), y.bytes()); + MemoryVector bits(2*part_size); + + x.binary_encode(&bits[part_size - x.bytes()]); + y.binary_encode(&bits[2*part_size - y.bytes()]); + return string((const char*)bits.begin(), (const char*)bits.end()); +} + +std::string ECDSADNSPrivateKey::sign(const std::string& hash) const +{ + ECDSA_Signature_Operation ops(*d_key); + AutoSeeded_RNG rng; + SecureVector signature=ops.sign((byte*)hash.c_str(), hash.length(), rng); + + return string((const char*)signature.begin(), (const char*) signature.end()); +} + +bool ECDSADNSPrivateKey::verify(const std::string& hash, const std::string& signature) const +{ + ECDSA_Verification_Operation ops(*d_key); + return ops.verify ((byte*)hash.c_str(), hash.length(), (byte*)signature.c_str(), signature.length()); +} + +namespace { +struct LoaderStruct +{ + LoaderStruct() + { + //DNSPrivateKey::report(12, &GOSTDNSPrivateKey::maker); + DNSPrivateKey::report(13, &ECDSADNSPrivateKey::maker); + DNSPrivateKey::report(14, &ECDSADNSPrivateKey::maker); + } +} loader; +} diff --git a/pdns/dbdnsseckeeper.cc b/pdns/dbdnsseckeeper.cc index f60b168ad6..e2d31bb49e 100644 --- a/pdns/dbdnsseckeeper.cc +++ b/pdns/dbdnsseckeeper.cc @@ -78,10 +78,21 @@ bool DNSSECKeeper::isPresigned(const std::string& name) void DNSSECKeeper::addKey(const std::string& name, bool keyOrZone, int algorithm, int bits, bool active) { - if(!bits) - bits = keyOrZone ? 2048 : 1024; + if(!bits) { + if(algorithm <= 10) + bits = keyOrZone ? 2048 : 1024; + else { + if(algorithm == 13) + bits = 256; + else if(algorithm == 14) + bits = 384; + else { + throw runtime_error("Can't guess key size for algoritm "+lexical_cast(algorithm)); + } + } + } DNSSECPrivateKey dspk; - shared_ptr dpk(new RSADNSPrivateKey); // defaults to RSA for now, could be smart w/algorithm! XXX FIXME + shared_ptr dpk(DNSPrivateKey::make(algorithm)); // defaults to RSA for now, could be smart w/algorithm! XXX FIXME dpk->create(bits); dspk.setKey(dpk); dspk.d_algorithm = algorithm; @@ -130,7 +141,7 @@ DNSSECPrivateKey DNSSECKeeper::getKeyById(const std::string& zname, unsigned int DNSSECPrivateKey dpk; DNSKEYRecordContent dkrc; - dpk.setKey(shared_ptr(DNSPrivateKey::fromISCString(dkrc, kd.content))); + dpk.setKey(shared_ptr(DNSPrivateKey::makeFromISCString(dkrc, kd.content))); dpk.d_flags = kd.flags; dpk.d_algorithm = dkrc.d_algorithm; @@ -276,7 +287,7 @@ DNSSECKeeper::keyset_t DNSSECKeeper::getKeys(const std::string& zone, boost::tri DNSSECPrivateKey dpk; DNSKEYRecordContent dkrc; - dpk.setKey(shared_ptr(DNSPrivateKey::fromISCString(dkrc, kd.content))); + dpk.setKey(shared_ptr(DNSPrivateKey::makeFromISCString(dkrc, kd.content))); dpk.d_flags = kd.flags; dpk.d_algorithm = dkrc.d_algorithm; if(dpk.d_algorithm == 5 && getNSEC3PARAM(zone)) diff --git a/pdns/dnssecinfra.cc b/pdns/dnssecinfra.cc index 7835d428c7..0110508c74 100644 --- a/pdns/dnssecinfra.cc +++ b/pdns/dnssecinfra.cc @@ -7,14 +7,12 @@ #include "iputils.hh" #include #include -#include -#include -#include -#include #include "dnssecinfra.hh" #include "dnsseckeeper.hh" -#include -#include + +#include +#include +#include #include // for 'operator+=()' #include @@ -22,89 +20,7 @@ using namespace boost; using namespace std; using namespace boost::assign; -void RSADNSPrivateKey::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 RSADNSPrivateKey::getPubKeyHash() const -{ - unsigned char hash[20]; - unsigned char N[mpi_size(&d_context.N)]; - mpi_write_binary(&d_context.N, N, sizeof(N)); - unsigned char E[mpi_size(&d_context.E)]; - mpi_write_binary(&d_context.E, E, sizeof(E)); - - sha1_context ctx; - sha1_starts(&ctx); - sha1_update(&ctx, N, sizeof(N)); - sha1_update(&ctx, E, sizeof(E)); - sha1_finish(&ctx, hash); - return string((char*)hash, sizeof(hash)); -} - -std::string RSADNSPrivateKey::sign(const std::string& hash) const -{ - unsigned char signature[mpi_size(&d_context.N)]; - int ret=rsa_pkcs1_sign(const_cast(&d_context), RSA_PRIVATE, - hash.size()==20 ? SIG_RSA_SHA1 : SIG_RSA_SHA256, - hash.size(), - (const unsigned char*) hash.c_str(), signature); - - if(ret!=0) { - cerr<<"signing returned: "< > outputs_t; - outputs_t outputs; - push_back(outputs)("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: "+lexical_cast(algorithm); - switch(algorithm) { - case 5: - case 7 : - ret+= " (RSASHA1)"; - break; - case 8: - ret += " (RSASHA256)"; - break; - } - ret += "\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; -} - - -DNSPrivateKey* DNSPrivateKey::fromISCFile(DNSKEYRecordContent& drc, const char* fname) +DNSPrivateKey* DNSPrivateKey::makeFromISCFile(DNSKEYRecordContent& drc, const char* fname) { string sline, isc, key, value; FILE *fp=fopen(fname, "r"); @@ -120,21 +36,27 @@ DNSPrivateKey* DNSPrivateKey::fromISCFile(DNSKEYRecordContent& drc, const char* } fclose(fp); - switch(algorithm) { - case 5: - case 7: - case 8: - case 10: - return RSADNSPrivateKey::fromISCString(drc, isc); - break; - default: - throw runtime_error("Unknown DNSSEC signature algorithm number "+lexical_cast(algorithm)); - break; + DNSPrivateKey* dpk=make(algorithm); + dpk->fromISCString(drc, isc); + return dpk; +} + +DNSPrivateKey* DNSPrivateKey::make(unsigned int algo) +{ + makers_t& makers = getMakers(); + makers_t::const_iterator iter = makers.find(algo); + if(iter != makers.end()) + return (iter->second)(algo); + else { + throw runtime_error("Request to create key object for unknown algorithm number "+lexical_cast(algo)); } - return 0; } -DNSPrivateKey* DNSPrivateKey::fromISCString(DNSKEYRecordContent& drc, const std::string& content) +void DNSPrivateKey::report(unsigned int algo, maker_t* maker) +{ + getMakers()[algo]=maker; +} +DNSPrivateKey* DNSPrivateKey::makeFromISCString(DNSKEYRecordContent& drc, const std::string& content) { int algorithm = 0; string sline, key, value; @@ -146,147 +68,31 @@ DNSPrivateKey* DNSPrivateKey::fromISCString(DNSKEYRecordContent& drc, const std: break; } } - switch(algorithm) { - case 5: - case 7: - case 8: - case 10: - return RSADNSPrivateKey::fromISCString(drc, content); - break; - default: - throw runtime_error("Unknown DNSSEC signature algorithm number "+lexical_cast(algorithm)); - break; - } - return 0; -} - -DNSPrivateKey* RSADNSPrivateKey::fromISCString(DNSKEYRecordContent& drc, const std::string& content) -{ - RSADNSPrivateKey* ret = new RSADNSPrivateKey(); - - string sline; - string key,value; - map places; - - rsa_init(&ret->d_context, RSA_PKCS_V15, 0, NULL, NULL ); - - places["Modulus"]=&ret->d_context.N; - places["PublicExponent"]=&ret->d_context.E; - places["PrivateExponent"]=&ret->d_context.D; - places["Prime1"]=&ret->d_context.P; - places["Prime2"]=&ret->d_context.Q; - places["Exponent1"]=&ret->d_context.DP; - places["Exponent2"]=&ret->d_context.DQ; - places["Coefficient"]=&ret->d_context.QP; - - string modulus, exponent; - istringstream str(content); - unsigned char decoded[1024]; - while(getline(str, sline)) { - tie(key,value)=splitField(sline, ':'); - trim(value); - - if(places.count(key)) { - if(places[key]) { - int len=sizeof(decoded); - if(base64_decode(decoded, &len, (unsigned char*)value.c_str(), value.length()) < 0) { - cerr<<"Error base64 decoding '"<d_context.len = ( mpi_msb( &ret->d_context.N ) + 7 ) >> 3; // no clue what this does - - if(exponent.length() < 255) - drc.d_key.assign(1, (char) (unsigned int) exponent.length()); - else { - drc.d_key.assign(1, 0); - uint16_t len=htons(exponent.length()); - drc.d_key.append((char*)&len, 2); - } - drc.d_key.append(exponent); - drc.d_key.append(modulus); - drc.d_protocol=3; - - return ret; + DNSPrivateKey* dpk=make(algorithm); + dpk->fromISCString(drc, content); + return dpk; } -DNSPrivateKey* DNSPrivateKey::fromPEMString(DNSKEYRecordContent& drc, const std::string& raw) -{ - return RSADNSPrivateKey::fromPEMString(drc, raw); -} -DNSPrivateKey* RSADNSPrivateKey::fromPEMString(DNSKEYRecordContent& drc, const std::string& raw) +DNSPrivateKey* DNSPrivateKey::makeFromPEMString(DNSKEYRecordContent& drc, const std::string& raw) { - vector integers; - decodeDERIntegerSequence(raw, integers); - cerr<<"Got "< places; - RSADNSPrivateKey* ret = new RSADNSPrivateKey; - - rsa_init(&ret->d_context, RSA_PKCS_V15, 0, NULL, NULL ); - - places[1]=&ret->d_context.N; - places[2]=&ret->d_context.E; - places[3]=&ret->d_context.D; - places[4]=&ret->d_context.P; - places[5]=&ret->d_context.Q; - places[6]=&ret->d_context.DP; - places[7]=&ret->d_context.DQ; - places[8]=&ret->d_context.QP; - - string modulus, exponent; - - for(int n = 0; n < 9 ; ++n) { - if(places.count(n)) { - if(places[n]) { - mpi_read_binary(places[n], (const unsigned char*)integers[n].c_str(), integers[n].length()); - if(n==1) - modulus=integers[n]; - if(n==2) - exponent=integers[n]; - } + BOOST_FOREACH(makers_t::value_type& val, getMakers()) + { + DNSPrivateKey* ret=0; + try { + ret = val.second(val.first); + ret->fromPEMString(drc, raw); + return ret; + } + catch(...) + { + delete ret; // fine if 0 } } - ret->d_context.len = ( mpi_msb( &ret->d_context.N ) + 7 ) >> 3; // no clue what this does - - if(exponent.length() < 255) - drc.d_key.assign(1, (char) (unsigned int) exponent.length()); - else { - drc.d_key.assign(1, 0); - uint16_t len=htons(exponent.length()); - drc.d_key.append((char*)&len, 2); - } - drc.d_key.append(exponent); - drc.d_key.append(modulus); - drc.d_protocol=3; - - return ret; + return 0; } -void makeRSAPublicKeyFromDNS(rsa_context* rc, const DNSKEYRecordContent& dkrc) -{ - rsa_init(rc, RSA_PKCS_V15, 0, NULL, NULL ); - - mpi_read_binary(&rc->E, (unsigned char*)dkrc.getExponent().c_str(), dkrc.getExponent().length()); // exponent - mpi_read_binary(&rc->N, (unsigned char*)dkrc.getModulus().c_str(), dkrc.getModulus().length()); // modulus - rc->len = ( mpi_msb( &rc->N ) + 7 ) >> 3; // no clue what this does -} bool sharedDNSSECCompare(const shared_ptr& a, const shared_ptr& b) { @@ -315,14 +121,28 @@ string getHashForRRSET(const std::string& qname, const RRSIGRecordContent& rrc, toHash.append(rdata); } - if(rrc.d_algorithm <= 7 ) { + // algorithm 12 needs special GOST hash + + if(rrc.d_algorithm <= 7 ) { // RSASHA1 unsigned char hash[20]; sha1((unsigned char*)toHash.c_str(), toHash.length(), hash); return string((char*)hash, sizeof(hash)); - } else { + } else if(rrc.d_algorithm == 8 || rrc.d_algorithm == 13) { // RSASHA256 or ECDSAP256 unsigned char hash[32]; sha2((unsigned char*)toHash.c_str(), toHash.length(), hash, 0); return string((char*)hash, sizeof(hash)); + } else if(rrc.d_algorithm == 10) { // RSASHA512 + unsigned char hash[64]; + sha4((unsigned char*)toHash.c_str(), toHash.length(), hash, 0); + return string((char*)hash, sizeof(hash)); + } else if(rrc.d_algorithm == 14) { // ECDSAP384 + unsigned char hash[48]; + sha4((unsigned char*)toHash.c_str(), toHash.length(), hash, 1); // == 384 + return string((char*)hash, sizeof(hash)); + } + else { + cerr<<"No idea how to hash for algorithm "<<(int)rrc.d_algorithm<& output) { if(de.getOffset() - startseq != seqlen) throw runtime_error("DER Sequence ended before end of data"); - } - + } } diff --git a/pdns/dnssecinfra.hh b/pdns/dnssecinfra.hh index 99277c9f7d..57914e5421 100644 --- a/pdns/dnssecinfra.hh +++ b/pdns/dnssecinfra.hh @@ -1,22 +1,12 @@ #ifndef PDNS_DNSSECINFRA_HH #define PDNS_DNSSECINFRA_HH #include "dnsrecords.hh" -#include #include #include #include +#include #include "misc.hh" - -#define PDNSSEC_MI(x) mpi_init(&d_context.x, 0) -#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 DNSPrivateKey { public: @@ -27,96 +17,29 @@ class DNSPrivateKey virtual std::string getPublicKeyString()const =0; virtual int getBits() const =0; - static DNSPrivateKey* fromISCFile(DNSKEYRecordContent& drc, const char* fname); - static DNSPrivateKey* fromISCString(DNSKEYRecordContent& drc, const std::string& content); - static DNSPrivateKey* fromPEMString(DNSKEYRecordContent& drc, const std::string& raw); -}; - -class RSADNSPrivateKey : public DNSPrivateKey -{ -public: - RSADNSPrivateKey() - { - memset(&d_context, 0, sizeof(d_context)); - PDNSSEC_MI(N); - PDNSSEC_MI(E); PDNSSEC_MI(D); PDNSSEC_MI(P); PDNSSEC_MI(Q); PDNSSEC_MI(DP); PDNSSEC_MI(DQ); PDNSSEC_MI(QP); PDNSSEC_MI(RN); PDNSSEC_MI(RP); PDNSSEC_MI(RQ); - } - - ~RSADNSPrivateKey() - { - PDNSSEC_MF(N); - 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 RSADNSPrivateKey& 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); - } - - RSADNSPrivateKey(const RSADNSPrivateKey& orig) - { - d_context.ver = orig.d_context.ver; - d_context.len = orig.d_context.len; - - d_context.padding = orig.d_context.padding; - d_context.hash_id = orig.d_context.hash_id; - d_context.f_rng = orig.d_context.f_rng; - d_context.p_rng = orig.d_context.p_rng; + virtual void fromISCString(DNSKEYRecordContent& drc, const std::string& content)=0; + virtual void fromPEMString(DNSKEYRecordContent& drc, const std::string& raw)=0; - PDNSSEC_MC(N); - PDNSSEC_MC(E); PDNSSEC_MC(D); PDNSSEC_MC(P); PDNSSEC_MC(Q); PDNSSEC_MC(DP); PDNSSEC_MC(DQ); PDNSSEC_MC(QP); PDNSSEC_MC(RN); PDNSSEC_MC(RP); PDNSSEC_MC(RQ); - } - - RSADNSPrivateKey& operator=(const RSADNSPrivateKey& orig) - { - d_context.ver = orig.d_context.ver; - d_context.len = orig.d_context.len; - - d_context.padding = orig.d_context.padding; - d_context.hash_id = orig.d_context.hash_id; - d_context.f_rng = orig.d_context.f_rng; - d_context.p_rng = orig.d_context.p_rng; + static DNSPrivateKey* makeFromISCFile(DNSKEYRecordContent& drc, const char* fname); + static DNSPrivateKey* makeFromISCString(DNSKEYRecordContent& drc, const std::string& content); + static DNSPrivateKey* makeFromPEMString(DNSKEYRecordContent& drc, const std::string& raw); + static DNSPrivateKey* make(unsigned int algorithm); - PDNSSEC_MF(N); - 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); + typedef DNSPrivateKey* maker_t(unsigned int algorithm); - PDNSSEC_MC(N); - PDNSSEC_MC(E); PDNSSEC_MC(D); PDNSSEC_MC(P); PDNSSEC_MC(Q); PDNSSEC_MC(DP); PDNSSEC_MC(DQ); PDNSSEC_MC(QP); PDNSSEC_MC(RN); PDNSSEC_MC(RP); PDNSSEC_MC(RQ); - return *this; - } - - const rsa_context& getConstContext() const - { - return d_context; - } - - rsa_context& getContext() - { - return d_context; - } - - void create(unsigned int bits); - std::string convertToISC(unsigned int algorithm) const; - std::string getPubKeyHash() const; - std::string sign(const std::string& hash) const; - std::string getPublicKeyString() const; - int getBits() const - { - return mpi_size(&d_context.N)*8; - } - static DNSPrivateKey* fromISCString(DNSKEYRecordContent& drc, const std::string& content); - static DNSPrivateKey* fromPEMString(DNSKEYRecordContent& drc, const std::string& raw); - -private: - rsa_context d_context; + static void report(unsigned int algorithm, maker_t* maker); + private: + + typedef std::map makers_t; + + static makers_t& getMakers() + { + static makers_t s_makers; + return s_makers; + } + // need some magic here to pick the right DNSPrivateKey supplier }; -// see above -#undef PDNSSEC_MC -#undef PDNSSEC_MI -#undef PDNSSEC_MF - struct DNSSECPrivateKey { uint16_t getTag(); @@ -155,14 +78,9 @@ struct CanonicalCompare: public binary_function } }; - -DNSKEYRecordContent getRSAKeyFromISC(rsa_context* rsa, const char* fname); -DNSKEYRecordContent getRSAKeyFromISCString(rsa_context* rsa, const std::string& content); -DNSKEYRecordContent getRSAKeyFromPEMString(rsa_context* rsa, const std::string& content); -void makeRSAPublicKeyFromDNS(rsa_context* rc, const DNSKEYRecordContent& dkrc); bool sharedDNSSECCompare(const boost::shared_ptr& a, const shared_ptr& b); 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); diff --git a/pdns/pdnssec.cc b/pdns/pdnssec.cc index 80fa8ffe1b..7b22181939 100644 --- a/pdns/pdnssec.cc +++ b/pdns/pdnssec.cc @@ -311,6 +311,12 @@ try algorithm=5; else if(pdns_iequals(cmds[n], "rsasha256")) algorithm=8; + else if(pdns_iequals(cmds[n], "gost")) + algorithm=10; + else if(pdns_iequals(cmds[n], "ecdsa256")) + algorithm=13; + else if(pdns_iequals(cmds[n], "ecdsa384")) + algorithm=14; else if(atoi(cmds[n].c_str())) bits = atoi(cmds[n].c_str()); else { @@ -436,7 +442,7 @@ try B64Decode(interim, raw); DNSSECPrivateKey dpk; DNSKEYRecordContent drc; - shared_ptr key(DNSPrivateKey::fromPEMString(drc, raw)); + shared_ptr key(DNSPrivateKey::makeFromPEMString(drc, raw)); dpk.setKey(key); dpk.d_algorithm = atoi(cmds[3].c_str()); @@ -471,7 +477,7 @@ try string fname=cmds[2]; DNSSECPrivateKey dpk; DNSKEYRecordContent drc; - shared_ptr key(DNSPrivateKey::fromISCFile(drc, fname.c_str())); + shared_ptr key(DNSPrivateKey::makeFromISCFile(drc, fname.c_str())); dpk.setKey(key); dpk.d_algorithm = drc.d_algorithm; diff --git a/pdns/polarrsakeyinfra.cc b/pdns/polarrsakeyinfra.cc new file mode 100644 index 0000000000..99a34faf96 --- /dev/null +++ b/pdns/polarrsakeyinfra.cc @@ -0,0 +1,350 @@ +#include +#include +#include +#include +#include +#include // for 'operator+=()' +#include +#include "dnssecinfra.hh" +using namespace boost::assign; + +#define PDNSSEC_MI(x) mpi_init(&d_context.x, 0) +#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) + +class RSADNSPrivateKey : public DNSPrivateKey +{ +public: + RSADNSPrivateKey() + { + memset(&d_context, 0, sizeof(d_context)); + PDNSSEC_MI(N); + PDNSSEC_MI(E); PDNSSEC_MI(D); PDNSSEC_MI(P); PDNSSEC_MI(Q); PDNSSEC_MI(DP); PDNSSEC_MI(DQ); PDNSSEC_MI(QP); PDNSSEC_MI(RN); PDNSSEC_MI(RP); PDNSSEC_MI(RQ); + } + + ~RSADNSPrivateKey() + { + PDNSSEC_MF(N); + 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 RSADNSPrivateKey& 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); + } + + RSADNSPrivateKey(const RSADNSPrivateKey& orig) + { + d_context.ver = orig.d_context.ver; + d_context.len = orig.d_context.len; + + d_context.padding = orig.d_context.padding; + d_context.hash_id = orig.d_context.hash_id; + d_context.f_rng = orig.d_context.f_rng; + d_context.p_rng = orig.d_context.p_rng; + + PDNSSEC_MC(N); + PDNSSEC_MC(E); PDNSSEC_MC(D); PDNSSEC_MC(P); PDNSSEC_MC(Q); PDNSSEC_MC(DP); PDNSSEC_MC(DQ); PDNSSEC_MC(QP); PDNSSEC_MC(RN); PDNSSEC_MC(RP); PDNSSEC_MC(RQ); + } + + RSADNSPrivateKey& operator=(const RSADNSPrivateKey& orig) + { + d_context.ver = orig.d_context.ver; + d_context.len = orig.d_context.len; + + d_context.padding = orig.d_context.padding; + d_context.hash_id = orig.d_context.hash_id; + d_context.f_rng = orig.d_context.f_rng; + d_context.p_rng = orig.d_context.p_rng; + + PDNSSEC_MF(N); + 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); + + PDNSSEC_MC(N); + PDNSSEC_MC(E); PDNSSEC_MC(D); PDNSSEC_MC(P); PDNSSEC_MC(Q); PDNSSEC_MC(DP); PDNSSEC_MC(DQ); PDNSSEC_MC(QP); PDNSSEC_MC(RN); PDNSSEC_MC(RP); PDNSSEC_MC(RQ); + return *this; + } + + const rsa_context& getConstContext() const + { + return d_context; + } + + rsa_context& getContext() + { + return d_context; + } + + void create(unsigned int bits); + std::string convertToISC(unsigned int algorithm) const; + std::string getPubKeyHash() const; + std::string sign(const std::string& hash) const; + std::string getPublicKeyString() const; + int getBits() const + { + return mpi_size(&d_context.N)*8; + } + void fromISCString(DNSKEYRecordContent& drc, const std::string& content); + void fromPEMString(DNSKEYRecordContent& drc, const std::string& raw); + + static DNSPrivateKey* maker(unsigned int) + { + return new RSADNSPrivateKey(); + } + +private: + rsa_context d_context; +}; + +// see above +#undef PDNSSEC_MC +#undef PDNSSEC_MI +#undef PDNSSEC_MF + + +inline bool operator<(const mpi& a, const mpi& b) +{ + return mpi_cmp_mpi(&a, &b) < 0; +} + + +void RSADNSPrivateKey::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 RSADNSPrivateKey::getPubKeyHash() const +{ + unsigned char hash[20]; + unsigned char N[mpi_size(&d_context.N)]; + mpi_write_binary(&d_context.N, N, sizeof(N)); + unsigned char E[mpi_size(&d_context.E)]; + mpi_write_binary(&d_context.E, E, sizeof(E)); + + sha1_context ctx; + sha1_starts(&ctx); + sha1_update(&ctx, N, sizeof(N)); + sha1_update(&ctx, E, sizeof(E)); + sha1_finish(&ctx, hash); + return string((char*)hash, sizeof(hash)); +} + +std::string RSADNSPrivateKey::sign(const std::string& hash) const +{ + unsigned char signature[mpi_size(&d_context.N)]; + int hashKind; + if(hash.size()==20) + hashKind= SIG_RSA_SHA1; + else if(hash.size()==32) + hashKind= SIG_RSA_SHA256; + else + hashKind = SIG_RSA_SHA512; + + int ret=rsa_pkcs1_sign(const_cast(&d_context), RSA_PRIVATE, + hashKind, + hash.size(), + (const unsigned char*) hash.c_str(), signature); + + if(ret!=0) { + cerr<<"signing returned: "< > outputs_t; + outputs_t outputs; + push_back(outputs)("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: "+lexical_cast(algorithm); + switch(algorithm) { + case 5: + case 7 : + ret+= " (RSASHA1)"; + break; + case 8: + ret += " (RSASHA256)"; + break; + } + ret += "\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; +} + + +void RSADNSPrivateKey::fromISCString(DNSKEYRecordContent& drc, const std::string& content) +{ + string sline; + string key,value; + map places; + + rsa_init(&d_context, RSA_PKCS_V15, 0, NULL, NULL ); + + places["Modulus"]=&d_context.N; + places["PublicExponent"]=&d_context.E; + places["PrivateExponent"]=&d_context.D; + places["Prime1"]=&d_context.P; + places["Prime2"]=&d_context.Q; + places["Exponent1"]=&d_context.DP; + places["Exponent2"]=&d_context.DQ; + places["Coefficient"]=&d_context.QP; + + string modulus, exponent; + istringstream str(content); + unsigned char decoded[1024]; + while(getline(str, sline)) { + tie(key,value)=splitField(sline, ':'); + trim(value); + + if(places.count(key)) { + if(places[key]) { + int len=sizeof(decoded); + if(base64_decode(decoded, &len, (unsigned char*)value.c_str(), value.length()) < 0) { + cerr<<"Error base64 decoding '"<> 3; // no clue what this does + + if(exponent.length() < 255) + drc.d_key.assign(1, (char) (unsigned int) exponent.length()); + else { + drc.d_key.assign(1, 0); + uint16_t len=htons(exponent.length()); + drc.d_key.append((char*)&len, 2); + } + drc.d_key.append(exponent); + drc.d_key.append(modulus); + drc.d_protocol=3; +} + +void RSADNSPrivateKey::fromPEMString(DNSKEYRecordContent& drc, const std::string& raw) +{ + vector integers; + decodeDERIntegerSequence(raw, integers); + cerr<<"Got "< places; + + rsa_init(&d_context, RSA_PKCS_V15, 0, NULL, NULL ); + + places[1]=&d_context.N; + places[2]=&d_context.E; + places[3]=&d_context.D; + places[4]=&d_context.P; + places[5]=&d_context.Q; + places[6]=&d_context.DP; + places[7]=&d_context.DQ; + places[8]=&d_context.QP; + + string modulus, exponent; + + for(int n = 0; n < 9 ; ++n) { + if(places.count(n)) { + if(places[n]) { + mpi_read_binary(places[n], (const unsigned char*)integers[n].c_str(), integers[n].length()); + if(n==1) + modulus=integers[n]; + if(n==2) + exponent=integers[n]; + } + } + } + d_context.len = ( mpi_msb( &d_context.N ) + 7 ) >> 3; // no clue what this does + + if(exponent.length() < 255) + drc.d_key.assign(1, (char) (unsigned int) exponent.length()); + else { + drc.d_key.assign(1, 0); + uint16_t len=htons(exponent.length()); + drc.d_key.append((char*)&len, 2); + } + drc.d_key.append(exponent); + drc.d_key.append(modulus); + drc.d_protocol=3; +} +#if 0 +void makeRSAPublicKeyFromDNS(rsa_context* rc, const DNSKEYRecordContent& dkrc) +{ + rsa_init(rc, RSA_PKCS_V15, 0, NULL, NULL ); + + mpi_read_binary(&rc->E, (unsigned char*)dkrc.getExponent().c_str(), dkrc.getExponent().length()); // exponent + mpi_read_binary(&rc->N, (unsigned char*)dkrc.getModulus().c_str(), dkrc.getModulus().length()); // modulus + rc->len = ( mpi_msb( &rc->N ) + 7 ) >> 3; // no clue what this does +} +#endif +string RSADNSPrivateKey::getPublicKeyString() const +{ + string keystring; + char tmp[max(mpi_size(&d_context.E), mpi_size(&d_context.N))]; + + mpi_write_binary(&d_context.E, (unsigned char*)tmp, mpi_size(&d_context.E) ); + string exponent((char*)tmp, mpi_size(&d_context.E)); + + mpi_write_binary(&d_context.N, (unsigned char*)tmp, mpi_size(&d_context.N) ); + string modulus((char*)tmp, mpi_size(&d_context.N)); + + if(exponent.length() < 255) + keystring.assign(1, (char) (unsigned int) exponent.length()); + else { + keystring.assign(1, 0); + uint16_t len=htons(exponent.length()); + keystring.append((char*)&len, 2); + } + keystring.append(exponent); + keystring.append(modulus); + return keystring; +} +namespace { +struct LoaderStruct +{ + LoaderStruct() + { + DNSPrivateKey::report(5, &RSADNSPrivateKey::maker); + DNSPrivateKey::report(7, &RSADNSPrivateKey::maker); + DNSPrivateKey::report(8, &RSADNSPrivateKey::maker); + DNSPrivateKey::report(10, &RSADNSPrivateKey::maker); + } +} loader; +} -- 2.47.3