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

Revision 1551, 10.2 KB (checked in by ahu, 3 years ago)

initial drop of dnssec keying infrastructure - mostly ceremonial

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