From: Bert Hubert Date: Fri, 14 Jan 2011 22:12:31 +0000 (+0000) Subject: implement 'pdnssec import-zone-key-pem' which is compatible with the default output... X-Git-Tag: auth-3.0~363 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ed3f855902fc73284d74b77852fa1746461d15f2;p=pdns implement 'pdnssec import-zone-key-pem' which is compatible with the default output of openssl genrsa. This should aid interoperability with non-DNSSEC RSA key generators. Thanks to Martin van Hensbergen for helping us navigate the jungle of PEM/BER/DER/PKCS standards. git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@1884 d19b8d6e-7fed-0310-83ef-9ca221ded41b --- diff --git a/pdns/dnssecinfra.cc b/pdns/dnssecinfra.cc index c11eb9430..2d652e315 100644 --- a/pdns/dnssecinfra.cc +++ b/pdns/dnssecinfra.cc @@ -224,6 +224,53 @@ DNSKEYRecordContent getRSAKeyFromISCString(rsa_context* rsa, const std::string& return drc; } +DNSKEYRecordContent getRSAKeyFromPEMString(rsa_context* rsa, const std::string& raw) +{ + vector integers; + decodeDERIntegerSequence(raw, integers); + cerr<<"Got "< places; + + rsa_init(rsa, RSA_PKCS_V15, 0, NULL, NULL ); + + places[1]=&rsa->N; + places[2]=&rsa->E; + places[3]=&rsa->D; + places[4]=&rsa->P; + places[5]=&rsa->Q; + places[6]=&rsa->DP; + places[7]=&rsa->DQ; + places[8]=&rsa->QP; + + DNSKEYRecordContent drc; + 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]; + } + } + } + rsa->len = ( mpi_msb( &rsa->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 drc; +} void makeRSAPublicKeyFromDNS(rsa_context* rc, const DNSKEYRecordContent& dkrc) @@ -369,3 +416,81 @@ DNSKEYRecordContent DNSSECPrivateKey::getDNSKEY() const { return makeDNSKEYFromRSAKey(&d_key.getConstContext(), d_algorithm, d_flags); } + +class DEREater +{ +public: + DEREater(const std::string& str) : d_str(str), d_pos(0) + {} + + struct eof{}; + + uint8_t getByte() + { + if(d_pos >= d_str.length()) { + throw eof(); + } + return (uint8_t) d_str[d_pos++]; + } + + uint32_t getLength() + { + uint8_t first = getByte(); + if(first < 0x80) { + return first; + } + first &= ~0x80; + + uint32_t len=0; + for(int n=0; n < first; ++n) { + len *= 0x100; + len += getByte(); + } + return len; + } + + std::string getBytes(unsigned int len) + { + std::string ret; + for(unsigned int n=0; n < len; ++n) + ret.append(1, (char)getByte()); + return ret; + } + + std::string::size_type getOffset() + { + return d_pos; + } +private: + const std::string& d_str; + std::string::size_type d_pos; +}; + +void decodeDERIntegerSequence(const std::string& input, vector& output) +{ + output.clear(); + DEREater de(input); + if(de.getByte() != 0x30) + throw runtime_error("Not a DER sequence"); + + unsigned int seqlen=de.getLength(); + unsigned int startseq=de.getOffset(); + unsigned int len; + string ret; + try { + for(;;) { + uint8_t kind = de.getByte(); + if(kind != 0x02) + throw runtime_error("DER Sequence contained non-INTEGER component: "+lexical_cast((unsigned int)kind) ); + len = de.getLength(); + ret = de.getBytes(len); + output.push_back(ret); + } + } + catch(DEREater::eof& eof) + { + 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 feb1ed93f..49682e263 100644 --- a/pdns/dnssecinfra.hh +++ b/pdns/dnssecinfra.hh @@ -25,6 +25,7 @@ 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); @@ -47,5 +48,6 @@ int getRRSIGsForRRSET(DNSSECKeeper& dk, const std::string signQName, uint16_t si vector >& toSign, vector &rrc, bool ksk); std::string hashQNameWithSalt(unsigned int times, const std::string& salt, const std::string& qname); +void decodeDERIntegerSequence(const std::string& input, vector& output); #endif diff --git a/pdns/docs/pdns.xml b/pdns/docs/pdns.xml index bd09a521c..832e63f51 100644 --- a/pdns/docs/pdns.xml +++ b/pdns/docs/pdns.xml @@ -9315,7 +9315,7 @@ $ pdnssec rectify-zone - export-zone-dnskey ZONE KEY-ID + export-zone-key ZONE KEY-ID Export to standard output full (private) key with key id KEY-ID within zone called ZONE. The format @@ -9333,7 +9333,7 @@ $ pdnssec rectify-zone - import-zone-dnskey ZONE filename [ksk|zsk] + import-zone-key ZONE filename [ksk|zsk] Import from 'filename' a full (private) key for zone called ZONE. The format @@ -9342,6 +9342,17 @@ $ pdnssec rectify-zone + + import-zone-key-pem ZONE filename algorithm [ksk|zsk] + + + Import from 'filename' a full (private) key in PEM format for zone called ZONE, and + assign it an algorithm number. KSK or ZSK specifies the flags this + key should have on import. The format used is compatible with 'openssl genrsa', + which is also called PEM. + + + rectify-zone ZONE @@ -9547,7 +9558,7 @@ $ pdnssec rectify-zone Olaf Kolkman (NLNetLabs) Wouter Wijngaards (NLNetLabs) Marco Davids (SIDN) - Marcus Travaille (SIDN) + Markus Travaille (SIDN) Antoin Verschuren (SIDN) Olafur Guðmundsson (IETF) Dan Kaminsky (Recursion Ventures) @@ -9565,6 +9576,7 @@ $ pdnssec rectify-zone Johannes Kuehrer (Austrian World4You GmbH) Marc van de Geijn (bHosted.nl) Stefan Arentz + Martin van Hensbergen (Fox-IT) .. this list is far from complete yet .. diff --git a/pdns/pdnssec.cc b/pdns/pdnssec.cc index a4074f535..32f0e8508 100644 --- a/pdns/pdnssec.cc +++ b/pdns/pdnssec.cc @@ -2,6 +2,7 @@ #include "dnssecinfra.hh" #include "statbag.hh" #include "base32.hh" +#include "base64.hh" #include #include #include "dnsbackend.hh" @@ -397,6 +398,49 @@ try DNSSECPrivateKey dpk=dk.getKeyById(zone, id); cout << dpk.d_key.convertToISC(dpk.d_algorithm) < 4) { + if(pdns_iequals(cmds[4], "ZSK")) + dpk.d_flags = 256; + else if(pdns_iequals(cmds[4], "KSK")) + dpk.d_flags = 257; + else { + cerr<<"Unknown key flag '"<