]> granicus.if.org Git - pdns/commitdiff
implement 'pdnssec import-zone-key-pem' which is compatible with the default output...
authorBert Hubert <bert.hubert@netherlabs.nl>
Fri, 14 Jan 2011 22:12:31 +0000 (22:12 +0000)
committerBert Hubert <bert.hubert@netherlabs.nl>
Fri, 14 Jan 2011 22:12:31 +0000 (22:12 +0000)
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

pdns/dnssecinfra.cc
pdns/dnssecinfra.hh
pdns/docs/pdns.xml
pdns/pdnssec.cc

index c11eb94303fcf3c8e52b8179367d2e8168cb8450..2d652e315c742c8531cf55deaff73a0b98e9fece 100644 (file)
@@ -224,6 +224,53 @@ DNSKEYRecordContent getRSAKeyFromISCString(rsa_context* rsa, const std::string&
   return drc;
 }
 
+DNSKEYRecordContent getRSAKeyFromPEMString(rsa_context* rsa, const std::string& raw)
+{
+  vector<string> integers;
+  decodeDERIntegerSequence(raw, integers);
+  cerr<<"Got "<<integers.size()<<" integers"<<endl; 
+  map<int, mpi*> 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<string>& 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<string>((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");
+  }
+  
+}
index feb1ed93f8d90fd7f9c7f9d64151360b3a03f7ed..49682e2637bead740241e6b374d8c489f3012728 100644 (file)
@@ -25,6 +25,7 @@ struct CanonicalCompare: public binary_function<string, string, bool>
 
 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<DNSRecordContent>& a, const shared_ptr<DNSRecordContent>& b);
 string getHashForRRSET(const std::string& qname, const RRSIGRecordContent& rrc, std::vector<boost::shared_ptr<DNSRecordContent> >& signRecords);
@@ -47,5 +48,6 @@ int getRRSIGsForRRSET(DNSSECKeeper& dk, const std::string signQName, uint16_t si
                     vector<shared_ptr<DNSRecordContent> >& toSign, vector<RRSIGRecordContent> &rrc, bool ksk);
 
 std::string hashQNameWithSalt(unsigned int times, const std::string& salt, const std::string& qname);
+void decodeDERIntegerSequence(const std::string& input, vector<string>& output);
 
 #endif
index bd09a521c6be079128270dc126cf442bd731d57a..832e63f51eb8b94ead178f263b518f0f7d7cd5a9 100644 (file)
@@ -9315,7 +9315,7 @@ $ pdnssec rectify-zone
            </listitem>
        </varlistentry>
        <varlistentry>
-           <term>export-zone-dnskey ZONE KEY-ID</term>
+           <term>export-zone-key ZONE KEY-ID</term>
            <listitem>
              <para>
                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
            </listitem>
        </varlistentry>
        <varlistentry>
-           <term>import-zone-dnskey ZONE filename [ksk|zsk]</term>
+           <term>import-zone-key ZONE filename [ksk|zsk]</term>
            <listitem>
              <para>
                Import from 'filename' a full (private) key for zone called ZONE. The format
@@ -9342,6 +9342,17 @@ $ pdnssec rectify-zone
              </para>
            </listitem>
        </varlistentry>
+       <varlistentry>
+           <term>import-zone-key-pem ZONE filename algorithm [ksk|zsk]</term>
+           <listitem>
+             <para>
+               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.
+             </para>
+           </listitem>
+       </varlistentry>
        <varlistentry>
            <term>rectify-zone ZONE</term>
            <listitem>
@@ -9547,7 +9558,7 @@ $ pdnssec rectify-zone
     <listitem><para>Olaf Kolkman (NLNetLabs)</para></listitem>
     <listitem><para>Wouter Wijngaards (NLNetLabs)</para></listitem>
     <listitem><para>Marco Davids (SIDN)</para></listitem>
-    <listitem><para>Marcus Travaille (SIDN)</para></listitem>
+    <listitem><para>Markus Travaille (SIDN)</para></listitem>
     <listitem><para>Antoin Verschuren (SIDN)</para></listitem>
     <listitem><para>Olafur Gu&eth;mundsson (IETF)</para></listitem>
     <listitem><para>Dan Kaminsky (Recursion Ventures)</para></listitem>
@@ -9565,6 +9576,7 @@ $ pdnssec rectify-zone
     <listitem><para>Johannes Kuehrer (Austrian World4You GmbH)</para></listitem>
     <listitem><para>Marc van de Geijn (bHosted.nl)</para></listitem>
     <listitem><para>Stefan Arentz</para></listitem>
+    <listitem><para>Martin van Hensbergen (Fox-IT)</para></listitem>
     <listitem><para>.. this list is far from complete yet .. </para></listitem>
     </itemizedlist>
 
index a4074f535fdf9f2a79da2bd6f2b1508e7eeab341..32f0e85082d3efff0838978b814b826fb1fc4cc9 100644 (file)
@@ -2,6 +2,7 @@
 #include "dnssecinfra.hh"
 #include "statbag.hh"
 #include "base32.hh"
+#include "base64.hh"
 #include <boost/foreach.hpp>
 #include <boost/program_options.hpp>
 #include "dnsbackend.hh"
@@ -397,6 +398,49 @@ try
     DNSSECPrivateKey dpk=dk.getKeyById(zone, id);
     cout << dpk.d_key.convertToISC(dpk.d_algorithm) <<endl;
   }  
+  else if(cmds[0]=="import-zone-key-pem") {
+    if(cmds.size() < 4) {
+      cerr<<"Syntax: pdnssec import-zone-key zone-name filename.pem algorithm [zsk|ksk]"<<endl;
+      exit(1);
+    }
+    string zone=cmds[1];
+    string fname=cmds[2];
+    string line;
+    ifstream ifs(fname.c_str());
+    string tmp, interim, raw;
+    while(getline(ifs, line)) {
+      if(line[0]=='-')
+        continue;
+      trim(line);
+      interim += line;
+    }
+    B64Decode(interim, raw);
+    DNSSECPrivateKey dpk;
+    getRSAKeyFromPEMString(&dpk.d_key.getContext(), raw);
+    
+    dpk.d_algorithm = atoi(cmds[3].c_str());
+    
+    if(dpk.d_algorithm == 7)
+      dpk.d_algorithm = 5;
+      
+    cerr<<(int)dpk.d_algorithm<<endl;
+    
+    if(cmds.size() > 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 '"<<cmds[4]<<"'\n";
+        exit(1);
+      }
+    }
+    else
+      dpk.d_flags = 257; // ksk
+      
+    dk.addKey(zone, dpk); 
+    
+  }
   else if(cmds[0]=="import-zone-key") {
     if(cmds.size() < 3) {
       cerr<<"Syntax: pdnssec import-zone-key zone-name filename [zsk|ksk]"<<endl;