Changeset 1884

Show
Ignore:
Timestamp:
01/14/11 23:12:31 (2 years ago)
Author:
ahu
Message:

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.

Location:
trunk/pdns/pdns
Files:
4 modified

Legend:

Unmodified
Added
Removed
  • trunk/pdns/pdns/dnssecinfra.cc

    r1879 r1884  
    225225} 
    226226 
     227DNSKEYRecordContent getRSAKeyFromPEMString(rsa_context* rsa, const std::string& raw) 
     228{ 
     229  vector<string> integers; 
     230  decodeDERIntegerSequence(raw, integers); 
     231  cerr<<"Got "<<integers.size()<<" integers"<<endl;  
     232  map<int, mpi*> places; 
     233   
     234  rsa_init(rsa, RSA_PKCS_V15, 0, NULL, NULL ); 
     235 
     236  places[1]=&rsa->N; 
     237  places[2]=&rsa->E; 
     238  places[3]=&rsa->D; 
     239  places[4]=&rsa->P; 
     240  places[5]=&rsa->Q; 
     241  places[6]=&rsa->DP; 
     242  places[7]=&rsa->DQ; 
     243  places[8]=&rsa->QP; 
     244 
     245  DNSKEYRecordContent drc; 
     246  string modulus, exponent; 
     247   
     248  for(int n = 0; n < 9 ; ++n) { 
     249    if(places.count(n)) { 
     250      if(places[n]) { 
     251        mpi_read_binary(places[n], (const unsigned char*)integers[n].c_str(), integers[n].length()); 
     252        if(n==1) 
     253          modulus=integers[n]; 
     254        if(n==2) 
     255          exponent=integers[n]; 
     256      } 
     257    } 
     258  } 
     259  rsa->len = ( mpi_msb( &rsa->N ) + 7 ) >> 3; // no clue what this does 
     260 
     261  if(exponent.length() < 255)  
     262    drc.d_key.assign(1, (char) (unsigned int) exponent.length()); 
     263  else { 
     264    drc.d_key.assign(1, 0); 
     265    uint16_t len=htons(exponent.length()); 
     266    drc.d_key.append((char*)&len, 2); 
     267  } 
     268  drc.d_key.append(exponent); 
     269  drc.d_key.append(modulus); 
     270  drc.d_protocol=3; 
     271   
     272  return drc; 
     273} 
    227274 
    228275 
     
    370417  return makeDNSKEYFromRSAKey(&d_key.getConstContext(), d_algorithm, d_flags); 
    371418} 
     419 
     420class DEREater 
     421{ 
     422public: 
     423  DEREater(const std::string& str) : d_str(str), d_pos(0) 
     424  {} 
     425   
     426  struct eof{}; 
     427   
     428  uint8_t getByte() 
     429  { 
     430    if(d_pos >= d_str.length()) { 
     431      throw eof(); 
     432    } 
     433    return (uint8_t) d_str[d_pos++]; 
     434  } 
     435   
     436  uint32_t getLength() 
     437  { 
     438    uint8_t first = getByte(); 
     439    if(first < 0x80) { 
     440      return first; 
     441    } 
     442    first &= ~0x80; 
     443     
     444    uint32_t len=0; 
     445    for(int n=0; n < first; ++n) { 
     446      len *= 0x100; 
     447      len += getByte(); 
     448    } 
     449    return len; 
     450  } 
     451   
     452  std::string getBytes(unsigned int len) 
     453  { 
     454    std::string ret; 
     455    for(unsigned int n=0; n < len; ++n) 
     456      ret.append(1, (char)getByte()); 
     457    return ret; 
     458  } 
     459   
     460  std::string::size_type getOffset()  
     461  { 
     462    return d_pos; 
     463  } 
     464private: 
     465  const std::string& d_str; 
     466  std::string::size_type d_pos; 
     467}; 
     468 
     469void decodeDERIntegerSequence(const std::string& input, vector<string>& output) 
     470{ 
     471  output.clear(); 
     472  DEREater de(input); 
     473  if(de.getByte() != 0x30)  
     474    throw runtime_error("Not a DER sequence"); 
     475   
     476  unsigned int seqlen=de.getLength();  
     477  unsigned int startseq=de.getOffset(); 
     478  unsigned int len; 
     479  string ret; 
     480  try { 
     481    for(;;) { 
     482      uint8_t kind = de.getByte(); 
     483      if(kind != 0x02)  
     484        throw runtime_error("DER Sequence contained non-INTEGER component: "+lexical_cast<string>((unsigned int)kind) ); 
     485      len = de.getLength(); 
     486      ret = de.getBytes(len); 
     487      output.push_back(ret); 
     488    } 
     489  } 
     490  catch(DEREater::eof& eof) 
     491  { 
     492    if(de.getOffset() - startseq != seqlen) 
     493      throw runtime_error("DER Sequence ended before end of data"); 
     494  } 
     495   
     496} 
  • trunk/pdns/pdns/dnssecinfra.hh

    r1843 r1884  
    2626DNSKEYRecordContent getRSAKeyFromISC(rsa_context* rsa, const char* fname); 
    2727DNSKEYRecordContent getRSAKeyFromISCString(rsa_context* rsa, const std::string& content); 
     28DNSKEYRecordContent getRSAKeyFromPEMString(rsa_context* rsa, const std::string& content); 
    2829void makeRSAPublicKeyFromDNS(rsa_context* rc, const DNSKEYRecordContent& dkrc); 
    2930bool sharedDNSSECCompare(const boost::shared_ptr<DNSRecordContent>& a, const shared_ptr<DNSRecordContent>& b); 
     
    4849 
    4950std::string hashQNameWithSalt(unsigned int times, const std::string& salt, const std::string& qname); 
     51void decodeDERIntegerSequence(const std::string& input, vector<string>& output); 
    5052 
    5153#endif 
  • trunk/pdns/pdns/docs/pdns.xml

    r1865 r1884  
    93169316        </varlistentry> 
    93179317        <varlistentry> 
    9318             <term>export-zone-dnskey ZONE KEY-ID</term> 
     9318            <term>export-zone-key ZONE KEY-ID</term> 
    93199319            <listitem> 
    93209320              <para> 
     
    93349334        </varlistentry> 
    93359335        <varlistentry> 
    9336             <term>import-zone-dnskey ZONE filename [ksk|zsk]</term> 
     9336            <term>import-zone-key ZONE filename [ksk|zsk]</term> 
    93379337            <listitem> 
    93389338              <para> 
     
    93409340                used is compatible with BIND and NSD/LDNS. KSK or ZSK specifies the flags this 
    93419341                key should have on import. 
     9342              </para> 
     9343            </listitem> 
     9344        </varlistentry> 
     9345        <varlistentry> 
     9346            <term>import-zone-key-pem ZONE filename algorithm [ksk|zsk]</term> 
     9347            <listitem> 
     9348              <para> 
     9349                Import from 'filename' a full (private) key in PEM format for zone called ZONE, and 
     9350                assign it an algorithm number. KSK or ZSK specifies the flags this 
     9351                key should have on import. The format used is compatible with 'openssl genrsa', 
     9352                which is also called PEM. 
    93429353              </para> 
    93439354            </listitem> 
     
    95489559    <listitem><para>Wouter Wijngaards (NLNetLabs)</para></listitem> 
    95499560    <listitem><para>Marco Davids (SIDN)</para></listitem> 
    9550     <listitem><para>Marcus Travaille (SIDN)</para></listitem> 
     9561    <listitem><para>Markus Travaille (SIDN)</para></listitem> 
    95519562    <listitem><para>Antoin Verschuren (SIDN)</para></listitem> 
    95529563    <listitem><para>Olafur Gu&eth;mundsson (IETF)</para></listitem> 
     
    95669577    <listitem><para>Marc van de Geijn (bHosted.nl)</para></listitem> 
    95679578    <listitem><para>Stefan Arentz</para></listitem> 
     9579    <listitem><para>Martin van Hensbergen (Fox-IT)</para></listitem> 
    95689580    <listitem><para>.. this list is far from complete yet .. </para></listitem> 
    95699581    </itemizedlist> 
  • trunk/pdns/pdns/pdnssec.cc

    r1879 r1884  
    33#include "statbag.hh" 
    44#include "base32.hh" 
     5#include "base64.hh" 
    56#include <boost/foreach.hpp> 
    67#include <boost/program_options.hpp> 
     
    398399    cout << dpk.d_key.convertToISC(dpk.d_algorithm) <<endl; 
    399400  }   
     401  else if(cmds[0]=="import-zone-key-pem") { 
     402    if(cmds.size() < 4) { 
     403      cerr<<"Syntax: pdnssec import-zone-key zone-name filename.pem algorithm [zsk|ksk]"<<endl; 
     404      exit(1); 
     405    } 
     406    string zone=cmds[1]; 
     407    string fname=cmds[2]; 
     408    string line; 
     409    ifstream ifs(fname.c_str()); 
     410    string tmp, interim, raw; 
     411    while(getline(ifs, line)) { 
     412      if(line[0]=='-') 
     413        continue; 
     414      trim(line); 
     415      interim += line; 
     416    } 
     417    B64Decode(interim, raw); 
     418    DNSSECPrivateKey dpk; 
     419    getRSAKeyFromPEMString(&dpk.d_key.getContext(), raw); 
     420     
     421    dpk.d_algorithm = atoi(cmds[3].c_str()); 
     422     
     423    if(dpk.d_algorithm == 7) 
     424      dpk.d_algorithm = 5; 
     425       
     426    cerr<<(int)dpk.d_algorithm<<endl; 
     427     
     428    if(cmds.size() > 4) { 
     429      if(pdns_iequals(cmds[4], "ZSK")) 
     430        dpk.d_flags = 256; 
     431      else if(pdns_iequals(cmds[4], "KSK")) 
     432        dpk.d_flags = 257; 
     433      else { 
     434        cerr<<"Unknown key flag '"<<cmds[4]<<"'\n"; 
     435        exit(1); 
     436      } 
     437    } 
     438    else 
     439      dpk.d_flags = 257; // ksk 
     440       
     441    dk.addKey(zone, dpk);  
     442     
     443  } 
    400444  else if(cmds[0]=="import-zone-key") { 
    401445    if(cmds.size() < 3) {