root/trunk/pdns/pdns/dnssecinfra.cc @ 1768

Revision 1768, 10.3 KB (checked in by ahu, 2 years ago)

silence some debugging output, clarify some comments

Line 
1#include "dnsparser.hh"
2#include "sstuff.hh"
3#include "misc.hh"
4#include "dnswriter.hh"
5#include "dnsrecords.hh"
6#include "statbag.hh"
7#include "iputils.hh"
8#include <boost/foreach.hpp>
9#include <boost/algorithm/string.hpp>
10#include <polarssl/rsa.h>
11#include <polarssl/base64.h>
12#include <polarssl/sha1.h>
13#include <polarssl/sha2.h>
14#include "dnssecinfra.hh"
15#include "dnsseckeeper.hh"
16
17using namespace boost;
18using namespace std;
19
20DNSKEYRecordContent getRSAKeyFromISC(rsa_context* rsa, const char* fname)
21{
22  string sline;
23  string key,value;
24  map<string, mpi*> places;
25
26  FILE *fp=fopen(fname, "r");
27  if(!fp)
28    unixDie("opening file '"+string(fname)+"'");
29
30  rsa_init(rsa, RSA_PKCS_V15, 0, NULL, NULL );
31
32  places["Modulus"]=&rsa->N;
33  places["PublicExponent"]=&rsa->E;
34  places["PrivateExponent"]=&rsa->D;
35  places["Prime1"]=&rsa->P;
36  places["Prime2"]=&rsa->Q;
37  places["Exponent1"]=&rsa->DP;
38  places["Exponent2"]=&rsa->DQ;
39  places["Coefficient"]=&rsa->QP;
40
41  unsigned char decoded[1024];
42  DNSKEYRecordContent drc;
43  string modulus, exponent;
44  while(stringfgets(fp, sline)) {
45    tie(key,value)=splitField(sline, ':');
46    trim(value);
47
48    if(places.count(key)) {
49      if(places[key]) {
50
51        int len=sizeof(decoded);
52        if(base64_decode(decoded, &len, (unsigned char*)value.c_str(), value.length()) < 0) {
53          cerr<<"Error base64 decoding '"<<value<<"'\n";
54          exit(1);
55        }
56        //      B64Decode(value, decoded);
57        //      cerr<<key<<" decoded.length(): "<<8*len<<endl;
58        mpi_read_binary(places[key], decoded, len);
59        if(key=="Modulus")
60          modulus.assign((const char*)decoded,len);
61        if(key=="PublicExponent")
62          exponent.assign((const char*)decoded,len);
63      }
64    }
65    else {
66      if(key != "Private-key-format" && key != "Algorithm") 
67        cerr<<"Unknown field '"<<key<<"'\n";
68    }
69  }
70  rsa->len = ( mpi_msb( &rsa->N ) + 7 ) >> 3; // no clue what this does
71
72  if(exponent.length() < 255) 
73    drc.d_key.assign(1, (char) (unsigned int) exponent.length());
74  else {
75    drc.d_key.assign(1, 0);
76    uint16_t len=htons(exponent.length());
77    drc.d_key.append((char*)&len, 2);
78  }
79  drc.d_key.append(exponent);
80  drc.d_key.append(modulus);
81  drc.d_protocol=3;
82  drc.d_algorithm = 0; // should not be filled out here..
83  fclose(fp);
84  return drc;
85}
86
87
88void makeRSAPublicKeyFromDNS(rsa_context* rc, const DNSKEYRecordContent& dkrc)
89{
90  rsa_init(rc, RSA_PKCS_V15, 0, NULL, NULL );
91
92  mpi_read_binary(&rc->E, (unsigned char*)dkrc.getExponent().c_str(), dkrc.getExponent().length());    // exponent
93  mpi_read_binary(&rc->N, (unsigned char*)dkrc.getModulus().c_str(), dkrc.getModulus().length());    // modulus
94  rc->len = ( mpi_msb( &rc->N ) + 7 ) >> 3; // no clue what this does
95}
96
97bool sharedDNSSECCompare(const shared_ptr<DNSRecordContent>& a, const shared_ptr<DNSRecordContent>& b)
98{
99  return a->serialize("", true) < b->serialize("", true);
100}
101
102string getSHA1HashForRRSET(const std::string& qname, const RRSIGRecordContent& rrc, vector<shared_ptr<DNSRecordContent> >& signRecords) 
103{
104  sort(signRecords.begin(), signRecords.end(), sharedDNSSECCompare);
105
106  string toHash;
107  toHash.append(const_cast<RRSIGRecordContent&>(rrc).serialize("", true));
108  toHash.resize(toHash.size() - rrc.d_signature.length()); // chop off the end;
109  //  cerr<<"toHash start size: "<<toHash.size()<<", signature length: "<<rrc.d_signature.length()<<endl;
110
111
112  BOOST_FOREACH(shared_ptr<DNSRecordContent>& add, signRecords) {
113    //  cerr<<"\t IN "<<rrc.d_originalttl<<"\t"<<add->getZoneRepresentation()<<"\n";
114    toHash.append(toLower(simpleCompress(qname, "")));
115    uint16_t tmp=htons(rrc.d_type);
116    toHash.append((char*)&tmp, 2);
117    tmp=htons(1); // class
118    toHash.append((char*)&tmp, 2);
119    uint32_t ttl=htonl(rrc.d_originalttl);
120    toHash.append((char*)&ttl, 4);
121    string rdata=add->serialize("", true);  // case issues hiding here..
122    tmp=htons(rdata.length());
123    toHash.append((char*)&tmp, 2);
124    toHash.append(rdata);
125  }
126  //  cerr<<"toHash: "<<makeHexDump(toHash)<<endl;
127  unsigned char hash[20];
128  sha1((unsigned char*)toHash.c_str(), toHash.length(), hash);
129  return string((char*)hash, 20);
130}
131
132DSRecordContent makeDSFromDNSKey(const std::string& qname, const DNSKEYRecordContent& drc, int digest)
133{
134  string toHash;
135  toHash.assign(toLower(simpleCompress(qname)));
136  toHash.append(const_cast<DNSKEYRecordContent&>(drc).serialize("", true));
137
138  unsigned char hash[32];
139  if(digest==1)
140    sha1((unsigned char*)toHash.c_str(), toHash.length(), hash);
141  else
142    sha2((unsigned char*)toHash.c_str(), toHash.length(), hash, 0);
143
144  DSRecordContent dsrc;
145  dsrc.d_algorithm= drc.d_algorithm;
146  dsrc.d_digesttype=digest;
147  dsrc.d_tag=const_cast<DNSKEYRecordContent&>(drc).getTag();
148  dsrc.d_digest.assign((const char*)hash, digest == 1 ? 20 : 32);
149  return dsrc;
150}
151
152DNSKEYRecordContent makeDNSKEYFromRSAKey(const rsa_context* rc, uint8_t algorithm, uint16_t flags)
153{
154  DNSKEYRecordContent drc;
155  char tmp[256];
156
157  //  cerr<<"in makeDNSKEY rsa_check_pubkey: "<<rsa_check_pubkey(rc)<<", bits="<<mpi_size(&rc->N)*8<<endl;
158
159  mpi_write_binary(&rc->E, (unsigned char*)tmp, mpi_size(&rc->E) );
160  string exponent((char*)tmp, mpi_size(&rc->E));
161
162  mpi_write_binary(&rc->N, (unsigned char*)tmp, mpi_size(&rc->N) );
163  string modulus((char*)tmp, mpi_size(&rc->N));
164
165  if(exponent.length() < 255) 
166    drc.d_key.assign(1, (char) (unsigned int) exponent.length());
167  else {
168    drc.d_key.assign(1, 0);
169    uint16_t len=htons(exponent.length());
170    drc.d_key.append((char*)&len, 2);
171  }
172  drc.d_key.append(exponent);
173  drc.d_key.append(modulus);
174
175  drc.d_protocol=3;
176  drc.d_algorithm = algorithm;
177
178  drc.d_flags=flags;
179
180  return drc;
181}
182
183bool getSignerFor(const std::string& keyRepositoryDir, const std::string& qname, std::string &signer)
184{
185  DNSSECKeeper dk(keyRepositoryDir); 
186
187  signer=qname;
188  do {
189    if(dk.haveActiveKSKFor(signer)) 
190      return true;
191  } while(chopOff(signer));
192  return false;
193}
194
195int countLabels(const std::string& signQName)
196{
197  int count =1;
198  for(string::const_iterator pos = signQName.begin(); pos != signQName.end() ; ++pos) 
199    if(*pos == '.' && pos+1 != signQName.end()) 
200      count++;
201
202  if(starts_with(signQName, "*."))
203    count--;
204  return count;
205}
206
207DNSKEYRecordContent getDNSKEYFor(const std::string& keyRepositoryDir, const std::string& qname, bool withKSK, RSAContext* rc)
208{
209  DNSSECKeeper dk(keyRepositoryDir);
210  cerr<<"Asked for a DNSKEY for '"<<qname<<"', withKSK="<<withKSK<<"\n";
211  DNSSECPrivateKey dpk;
212
213  if(!withKSK) {
214    DNSSECKeeper::keyset_t zskset=dk.getKeys(qname, false);
215    BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value, zskset) {
216      if(value.second.active) {
217        cerr<<"Found a ZSK for '"<<qname<<"', key tag = "<<value.first.getDNSKEY().getTag()<<endl;
218        *rc=value.first.d_key;
219        return value.first.getDNSKEY();
220      }
221      else 
222        cerr<<"Found an inactive ZSK for '"<<qname<<"', key tag = "<<value.first.getDNSKEY().getTag()<<endl;
223    }
224    cerr<<"Could not find an active ZSK for '"<<qname<<"'"<<endl;
225    exit(1);
226  }
227  else if(dk.haveActiveKSKFor(qname, &dpk)) {
228    cerr<<"Found a KSK for '"<<qname<<"'"<<endl;
229    *rc=dpk.d_key;
230    return dpk.getDNSKEY();
231  } else {
232      cerr<<"DID NOT FIND A ZSK for '"<<qname<<"'"<<endl;
233      exit(1);
234  }
235}
236
237// XXXX FIXME THINK ABOUT LOCKING HERE
238map<pair<string, uint16_t>, RRSIGRecordContent> g_rrsigs;
239
240void fillOutRRSIG(const std::string& keyrepodir, const std::string& signQName, RRSIGRecordContent& rrc, const std::string& hash, vector<shared_ptr<DNSRecordContent> >& toSign, bool withKSK) 
241{
242  RSAContext rc;
243
244  DNSKEYRecordContent drc =getDNSKEYFor(keyrepodir, rrc.d_signer, withKSK, &rc);
245  rrc.d_tag = drc.getTag();
246  rrc.d_algorithm = drc.d_algorithm;
247 
248  if(g_rrsigs.count(make_pair(hash, rrc.d_tag))) {
249    // cerr<<"RRSIG cache hit !"<<endl;
250    rrc = g_rrsigs[make_pair(hash, rrc.d_tag)];
251    return;
252  }
253   
254  string realhash=getSHA1HashForRRSET(signQName, rrc, toSign);
255
256  unsigned char signature[mpi_size(&rc.getContext().N)];
257
258  int ret=rsa_pkcs1_sign(&rc.getContext(), RSA_PRIVATE, SIG_RSA_SHA1, 20, (unsigned char*) realhash.c_str(), signature);
259 
260  if(ret!=0) {
261    cerr<<"signing returned: "<<ret<<endl;
262    exit(1);
263  }
264 
265  rrc.d_signature.assign((char*)signature, sizeof(signature));
266 
267  g_rrsigs[make_pair(hash, rrc.d_tag)] = rrc;
268
269}
270
271uint32_t getCurrentInception()
272{
273  uint32_t now = time(0);
274  now -= (now % (7*86400));
275  return now;
276}
277
278
279int getRRSIGForRRSET(const std::string& keyrepodir, const std::string signQName, uint16_t signQType, uint32_t signTTL, 
280                     vector<shared_ptr<DNSRecordContent> >& toSign, RRSIGRecordContent& rrc, bool ksk)
281{
282  if(toSign.empty())
283    return -1;
284
285  rrc.d_type=signQType;
286
287  // d_algorithm gets filled out by fillOutRRSIG, since it  gets the key
288  rrc.d_labels=countLabels(signQName); 
289  rrc.d_originalttl=signTTL; 
290  rrc.d_siginception=getCurrentInception();;
291  rrc.d_sigexpire = rrc.d_siginception + 14*86400;
292
293  rrc.d_tag=0;
294  if(!getSignerFor(keyrepodir, signQName, rrc.d_signer)) {
295    cerr<<"No signer known for '"<<signQName<<"'\n";
296    return -1;
297  }
298   
299  string hash= getSHA1HashForRRSET(signQName,  rrc, toSign);
300  fillOutRRSIG(keyrepodir, signQName, rrc, hash, toSign, ksk);
301  return 0;
302}
303
304void addSignature(const std::string& keyrepodir, const std::string signQName, const std::string& wildcardname, uint16_t signQType, uint32_t signTTL, DNSPacketWriter::Place signPlace, vector<shared_ptr<DNSRecordContent> >& toSign, DNSPacketWriter& pw)
305{
306  // cerr<<"Asked to sign '"<<signQName<<"'|"<<DNSRecordContent::NumberToType(signQType)<<", "<<toSign.size()<<" records\n";
307
308  RRSIGRecordContent rrc;
309  if(toSign.empty())
310    return;
311
312  for(int ksk = 0; ksk < 2; ++ksk) {
313    if(getRRSIGForRRSET(keyrepodir, wildcardname.empty() ? signQName : wildcardname, signQType, signTTL, toSign, rrc, ksk) < 0) {
314      cerr<<"Error signing a record!"<<endl;
315      return;
316    }
317   
318    pw.startRecord(signQName, QType::RRSIG, 3600, 1, 
319                   signQType==QType::DNSKEY ? DNSPacketWriter:: ANSWER : signPlace); 
320    rrc.toPacket(pw);
321   
322    pw.commit();
323    if(signQType != QType::DNSKEY)
324      break;
325  }
326
327  toSign.clear();
328}
329
330
331std::string hashQNameWithSalt(unsigned int times, const std::string& salt, const std::string& qname)
332{
333  string toHash;
334  toHash.assign(simpleCompress(toLower(qname)));
335  toHash.append(salt);
336
337//  cerr<<makeHexDump(toHash)<<endl;
338  unsigned char hash[20];
339  for(;;) {
340    sha1((unsigned char*)toHash.c_str(), toHash.length(), hash);
341    if(!times--) 
342      break;
343    toHash.assign((char*)hash, 20);
344    toHash.append(salt);
345  }
346  return string((char*)hash, 20);
347}
Note: See TracBrowser for help on using the browser.