root/trunk/pdns/pdns/dnssecsigner.cc @ 1905

Revision 1905, 6.3 KB (checked in by ahu, 2 years ago)

'multi-algorithm support' - for now we still only do RSA, but the whole signer stuff has been abstracted out, and we could in theory add KnapsackCRC32 code!
Or of course ECDSA or GOST ;-)

Line 
1/*
2    PowerDNS Versatile Database Driven Nameserver
3    Copyright (C) 2001 - 2011  PowerDNS.COM BV
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License version 2 as
7    published by the Free Software Foundation
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17*/
18#include "dnssecinfra.hh"
19#include "namespaces.hh"
20#include <boost/foreach.hpp>
21#include "dnsseckeeper.hh"
22#include "lock.hh"
23
24/* this is where the RRSIGs begin, keys are retrieved,
25   but the actual signing happens in fillOutRRSIG */
26int getRRSIGsForRRSET(DNSSECKeeper& dk, const std::string& signer, const std::string signQName, uint16_t signQType, uint32_t signTTL, 
27                     vector<shared_ptr<DNSRecordContent> >& toSign, vector<RRSIGRecordContent>& rrcs, bool ksk)
28{
29  if(toSign.empty())
30    return -1;
31  RRSIGRecordContent rrc;
32  rrc.d_type=signQType;
33
34  rrc.d_labels=countLabels(signQName); 
35  rrc.d_originalttl=signTTL; 
36  rrc.d_siginception=getCurrentInception();;
37  rrc.d_sigexpire = rrc.d_siginception + 14*86400; // XXX should come from zone metadata
38  rrc.d_signer = signer;
39  rrc.d_tag = 0;
40 
41  // we sign the RRSET in toSign + the rrc w/o hash
42 
43  DNSSECKeeper::keyset_t keys = dk.getKeys(rrc.d_signer);
44  vector<DNSSECPrivateKey> KSKs, ZSKs;
45  vector<DNSSECPrivateKey>* signingKeys;
46 
47  // if ksk==1, only get KSKs
48  // if ksk==0, get ZSKs, unless there is no ZSK, then get KSK
49  BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type& keymeta, keys) {
50    rrc.d_algorithm = keymeta.first.d_algorithm;
51    if(!keymeta.second.active) 
52      continue;
53     
54    if(keymeta.second.keyOrZone)
55      KSKs.push_back(keymeta.first);
56    else if(!ksk)
57      ZSKs.push_back(keymeta.first);
58  }
59  if(ksk)
60    signingKeys = &KSKs;
61  else {
62    if(ZSKs.empty())
63      signingKeys = &KSKs;
64    else
65      signingKeys =&ZSKs;
66  }
67 
68  BOOST_FOREACH(DNSSECPrivateKey& dpk, *signingKeys) {
69    fillOutRRSIG(dpk, signQName, rrc, toSign);
70    rrcs.push_back(rrc);
71  }
72  return 0;
73}
74
75// this is the entrypoint from DNSPacket
76void addSignature(DNSSECKeeper& dk, const std::string& signer, const std::string signQName, const std::string& wildcardname, uint16_t signQType, 
77  uint32_t signTTL, DNSPacketWriter::Place signPlace, 
78  vector<shared_ptr<DNSRecordContent> >& toSign, vector<DNSResourceRecord>& outsigned)
79{
80  // cerr<<"Asked to sign '"<<signQName<<"'|"<<DNSRecordContent::NumberToType(signQType)<<", "<<toSign.size()<<" records\n";
81  if(toSign.empty())
82    return;
83  vector<RRSIGRecordContent> rrcs;
84  if(dk.isPresigned(signer)) {
85    dk.getPreRRSIGs(signer, signQName, QType(signQType), signPlace, outsigned); // does it all
86  }
87  else {
88    if(getRRSIGsForRRSET(dk, signer, wildcardname.empty() ? signQName : wildcardname, signQType, signTTL, toSign, rrcs, signQType == QType::DNSKEY) < 0)  {
89      // cerr<<"Error signing a record!"<<endl;
90      return;
91    } 
92 
93    DNSResourceRecord rr;
94    rr.qname=signQName;
95    rr.qtype=QType::RRSIG;
96    rr.ttl=signTTL;
97    rr.auth=false;
98    rr.d_place = (DNSResourceRecord::Place) signPlace;
99    BOOST_FOREACH(RRSIGRecordContent& rrc, rrcs) {
100      rr.content = rrc.getZoneRepresentation();
101      outsigned.push_back(rr);
102    }
103  }
104  toSign.clear();
105}
106
107static pthread_mutex_t g_signatures_lock = PTHREAD_MUTEX_INITIALIZER;
108static map<pair<string, string>, string> g_signatures;
109
110void fillOutRRSIG(DNSSECPrivateKey& dpk, const std::string& signQName, RRSIGRecordContent& rrc, vector<shared_ptr<DNSRecordContent> >& toSign) 
111{
112  DNSKEYRecordContent drc = dpk.getDNSKEY(); 
113  const DNSPrivateKey* rc = dpk.getKey();
114  rrc.d_tag = drc.getTag();
115  rrc.d_algorithm = drc.d_algorithm;
116  string realhash=getHashForRRSET(signQName, rrc, toSign); // this is what we sign
117
118  pair<string, string> lookup(rc->getPubKeyHash(), realhash);
119 
120  {
121    Lock l(&g_signatures_lock);
122    if(g_signatures.count(lookup)) {
123      // cerr<<"Hit!"<<endl;
124      rrc.d_signature=g_signatures[lookup];
125      return;
126    }
127    else
128      ; // cerr<<"Miss!"<<endl;
129  }
130 
131  rrc.d_signature = rc->sign(realhash);
132
133  Lock l(&g_signatures_lock);
134  g_signatures[lookup] = rrc.d_signature;
135}
136
137static bool rrsigncomp(const DNSResourceRecord& a, const DNSResourceRecord& b)
138{
139  return a.d_place < b.d_place;
140}
141
142void addRRSigs(DNSSECKeeper& dk, const std::string& signer, DNSPacket& p)
143{
144  vector<DNSResourceRecord>& rrs=p.getRRS();
145 
146  stable_sort(rrs.begin(), rrs.end(), rrsigncomp);
147 
148  string signQName, wildcardQName;
149  uint16_t signQType=0;
150  uint32_t signTTL=0;
151 
152  DNSPacketWriter::Place signPlace=DNSPacketWriter::ANSWER;
153  vector<shared_ptr<DNSRecordContent> > toSign;
154
155  vector<DNSResourceRecord> signedRecords;
156
157  for(vector<DNSResourceRecord>::const_iterator pos = rrs.begin(); pos != rrs.end(); ++pos) {
158    signedRecords.push_back(*pos);
159    if(pos != rrs.begin() && (signQType != pos->qtype.getCode()  || signQName != pos->qname)) {
160      addSignature(dk, signer, signQName, wildcardQName, signQType, signTTL, signPlace, toSign, signedRecords);
161    }
162    signQName= pos->qname;
163    wildcardQName = pos->wildcardname;
164    signQType = pos ->qtype.getCode();
165    signTTL = pos->ttl;
166    signPlace = (DNSPacketWriter::Place) pos->d_place;
167    if(pos->auth || pos->qtype.getCode() == QType::DS) {
168      string content = pos->content;
169      if(pos->qtype.getCode()==QType::MX || pos->qtype.getCode() == QType::SRV) { 
170        content = lexical_cast<string>(pos->priority) + " " + pos->content;
171      }
172      if(!pos->content.empty() && pos->qtype.getCode()==QType::TXT && pos->content[0]!='"') {
173        content="\""+pos->content+"\"";
174      }
175      if(pos->content.empty())  // empty contents confuse the MOADNS setup
176        content=".";
177     
178      shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(pos->qtype.getCode(), 1, content)); 
179      toSign.push_back(drc);
180    }
181  }
182  addSignature(dk, signer, signQName, wildcardQName, signQType, signTTL, signPlace, toSign, signedRecords);
183 
184  rrs.swap(signedRecords);
185}
Note: See TracBrowser for help on using the browser.