]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dbdnsseckeeper.cc
quiet some nsec3 debugging output
[thirdparty/pdns.git] / pdns / dbdnsseckeeper.cc
CommitLineData
c0273500
BH
1#include "dnsseckeeper.hh"
2#include "dnssecinfra.hh"
3#include "ueberbackend.hh"
4#include "statbag.hh"
5#include <iostream>
6#include <boost/filesystem/operations.hpp>
7#include <boost/filesystem/path.hpp>
8#include <boost/foreach.hpp>
9#include <sys/stat.h>
10#include <sys/types.h>
11#include <fstream>
12#include <boost/algorithm/string.hpp>
13#include <boost/format.hpp>
14#include <boost/assign/std/vector.hpp> // for 'operator+=()'
15#include <boost/assign/list_inserter.hpp>
16using namespace boost::assign;
17namespace fs = boost::filesystem;
18
19using namespace std;
20using namespace boost;
21
e0d84497 22bool DNSSECKeeper::haveActiveKSKFor(const std::string& zone, DNSSECPrivateKey* dpk)
c0273500
BH
23{
24 keyset_t keys = getKeys(zone, true);
25 // need to get an *active* one!
26 //cerr<<__FUNCTION__<<"Got "<<keys.size()<<" keys"<<endl;
27 if(dpk && !keys.empty()) {
28 *dpk = keys.begin()->first;
29 }
30 return !keys.empty();
31}
32
33
34void DNSSECKeeper::addKey(const std::string& name, bool keyOrZone, int algorithm, int bits, bool active)
35{
36 if(!bits)
37 bits = keyOrZone ? 2048 : 1024;
38 DNSSECPrivateKey dpk;
39 dpk.d_key.create(bits);
f7bcc763
BH
40 addKey(name, keyOrZone, dpk, active);
41}
42
43void DNSSECKeeper::addKey(const std::string& name, bool keyOrZone, const DNSSECPrivateKey& dpk, bool active)
44{
c0273500
BH
45 DNSBackend::KeyData kd;
46 kd.flags = 256 + keyOrZone;
47 kd.active = active;
f7bcc763 48 kd.content = dpk.d_key.convertToISC(5);
c0273500
BH
49
50 // now store it
e0d84497 51 d_db.addDomainKey(name, kd);
c0273500
BH
52}
53
54
55static bool keyCompareByKindAndID(const DNSSECKeeper::keyset_t::value_type& a, const DNSSECKeeper::keyset_t::value_type& b)
56{
57 return make_pair(!a.second.keyOrZone, a.second.id) <
58 make_pair(!b.second.keyOrZone, b.second.id);
59}
60
61DNSSECPrivateKey DNSSECKeeper::getKeyById(const std::string& zname, unsigned int id)
62{
c0273500 63 vector<DNSBackend::KeyData> keys;
e0d84497 64 d_db.getDomainKeys(zname, 0, keys);
c0273500
BH
65 BOOST_FOREACH(const DNSBackend::KeyData& kd, keys) {
66 if(kd.id != id)
67 continue;
68
69 DNSSECPrivateKey dpk;
70
71 getRSAKeyFromISCString(&dpk.d_key.getContext(), kd.content);
72 dpk.d_flags = kd.flags;
73 dpk.d_algorithm = 5 + 2*getNSEC3PARAM(zname);
74
75 KeyMetaData kmd;
76
77 kmd.active = kd.active;
78 kmd.keyOrZone = (kd.flags == 257);
79 kmd.id = kd.id;
80
81 return dpk;
82 }
83 throw runtime_error("Can't find a key with id "+lexical_cast<string>(id)+" for zone '"+zname+"'");
c0273500
BH
84}
85
86
87void DNSSECKeeper::removeKey(const std::string& zname, unsigned int id)
88{
e0d84497 89 d_db.removeDomainKey(zname, id);
c0273500
BH
90}
91
92void DNSSECKeeper::deactivateKey(const std::string& zname, unsigned int id)
93{
e0d84497 94 d_db.deactivateDomainKey(zname, id);
c0273500
BH
95}
96
97void DNSSECKeeper::activateKey(const std::string& zname, unsigned int id)
98{
e0d84497 99 d_db.activateDomainKey(zname, id);
c0273500
BH
100}
101
102bool DNSSECKeeper::getNSEC3PARAM(const std::string& zname, NSEC3PARAMRecordContent* ns3p)
103{
e0d84497 104
c0273500 105 vector<string> meta;
e0d84497 106 d_db.getDomainMetadata(zname, "NSEC3PARAM", meta);
c0273500
BH
107
108 if(meta.empty())
109 return false;
110
111 if(ns3p) {
112 string descr = *meta.begin();
113 reportAllTypes();
114 NSEC3PARAMRecordContent* tmp=dynamic_cast<NSEC3PARAMRecordContent*>(DNSRecordContent::mastermake(QType::NSEC3PARAM, 1, descr));
115 if(!tmp) {
116 cerr<<"descr: '"<<descr<<"'\n";
117 return false;
118 }
119 *ns3p = *tmp;
120 delete tmp;
121 }
122 return true;
123}
124
125void DNSSECKeeper::setNSEC3PARAM(const std::string& zname, const NSEC3PARAMRecordContent& ns3p)
126{
127 string descr = ns3p.getZoneRepresentation();
128 vector<string> meta;
129 meta.push_back(descr);
e0d84497 130 d_db.setDomainMetadata(zname, "NSEC3PARAM", meta);
c0273500
BH
131}
132
133void DNSSECKeeper::unsetNSEC3PARAM(const std::string& zname)
134{
e0d84497 135 d_db.setDomainMetadata(zname, "NSEC3PARAM", vector<string>());
c0273500
BH
136}
137
138
e0d84497 139DNSSECKeeper::keyset_t DNSSECKeeper::getKeys(const std::string& zone, boost::tribool allOrKeyOrZone)
c0273500
BH
140{
141 keyset_t keyset;
c0273500
BH
142 vector<UeberBackend::KeyData> dbkeyset;
143
e0d84497 144 d_db.getDomainKeys(zone, 0, dbkeyset);
c0273500
BH
145 // do db thing
146 //cerr<<"Here: received " <<dbkeyset.size()<<" keys"<<endl;
147 BOOST_FOREACH(UeberBackend::KeyData& kd, dbkeyset)
148 {
149 DNSSECPrivateKey dpk;
150
151 getRSAKeyFromISCString(&dpk.d_key.getContext(), kd.content);
152 dpk.d_flags = kd.flags;
153 dpk.d_algorithm = 5 + 2*getNSEC3PARAM(zone);
154
155 KeyMetaData kmd;
156
157 kmd.active = kd.active;
158 kmd.keyOrZone = (kd.flags == 257);
159 kmd.id = kd.id;
160
161 if(boost::indeterminate(allOrKeyOrZone) || allOrKeyOrZone == kmd.keyOrZone)
162 keyset.push_back(make_pair(dpk, kmd));
163 }
164 sort(keyset.begin(), keyset.end(), keyCompareByKindAndID);
165 return keyset;
166}
167
168void DNSSECKeeper::secureZone(const std::string& name, int algorithm)
169{
170 addKey(name, true, algorithm);
171}
172
e0d84497 173bool getSignerFor(DNSSECKeeper& dk, const std::string& qname, std::string &signer)
f7bcc763 174{
f7bcc763
BH
175 signer=qname;
176 do {
177 if(dk.haveActiveKSKFor(signer))
178 return true;
179 } while(chopOff(signer));
180 return false;
181}
182
e0d84497
BH
183// this should be able to answer with multiple keys, in case of multiple active ZSKs XXX
184DNSKEYRecordContent getDNSKEYFor(DNSSECKeeper& dk, const std::string& qname, bool withKSK, RSAContext* rc)
f7bcc763 185{
e0d84497 186 // cerr<<"Asked for a DNSKEY for '"<<qname<<"', withKSK="<<withKSK<<"\n";
f7bcc763 187 DNSSECPrivateKey dpk;
c0273500 188
f7bcc763
BH
189 if(!withKSK) {
190 DNSSECKeeper::keyset_t zskset=dk.getKeys(qname, false);
191 BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value, zskset) {
192 if(value.second.active) {
e0d84497 193 // cerr<<"Found a ZSK for '"<<qname<<"', key tag = "<<value.first.getDNSKEY().getTag()<<endl;
f7bcc763
BH
194 *rc=value.first.d_key;
195 return value.first.getDNSKEY();
196 }
197 else
198 cerr<<"Found an inactive ZSK for '"<<qname<<"', key tag = "<<value.first.getDNSKEY().getTag()<<endl;
199 }
200 cerr<<"Could not find an active ZSK for '"<<qname<<"'"<<endl;
201 exit(1);
202 }
203 else if(dk.haveActiveKSKFor(qname, &dpk)) {
204 cerr<<"Found a KSK for '"<<qname<<"'"<<endl;
205 *rc=dpk.d_key;
206 return dpk.getDNSKEY();
207 } else {
208 cerr<<"DID NOT FIND A ZSK for '"<<qname<<"'"<<endl;
209 exit(1);
210 }
211}
212
e0d84497 213int getRRSIGForRRSET(DNSSECKeeper& dk, const std::string signQName, uint16_t signQType, uint32_t signTTL,
f7bcc763
BH
214 vector<shared_ptr<DNSRecordContent> >& toSign, RRSIGRecordContent& rrc, bool ksk)
215{
216 if(toSign.empty())
217 return -1;
218
219 rrc.d_type=signQType;
220
221 // d_algorithm gets filled out by fillOutRRSIG, since it gets the key
222 rrc.d_labels=countLabels(signQName);
223 rrc.d_originalttl=signTTL;
224 rrc.d_siginception=getCurrentInception();;
e0d84497 225 rrc.d_sigexpire = rrc.d_siginception + 14*86400; // XXX should come from zone metadata
f7bcc763
BH
226
227 rrc.d_tag=0;
e0d84497 228 if(!getSignerFor(dk, signQName, rrc.d_signer)) {
f7bcc763
BH
229 cerr<<"No signer known for '"<<signQName<<"'\n";
230 return -1;
231 }
232
233 string hash= getSHA1HashForRRSET(signQName, rrc, toSign);
e0d84497 234 fillOutRRSIG(dk, signQName, rrc, hash, toSign, ksk);
f7bcc763
BH
235 return 0;
236}
237
e0d84497 238void addSignature(DNSSECKeeper& dk, const std::string signQName, const std::string& wildcardname, uint16_t signQType, uint32_t signTTL, DNSPacketWriter::Place signPlace, vector<shared_ptr<DNSRecordContent> >& toSign, DNSPacketWriter& pw)
f7bcc763
BH
239{
240 // cerr<<"Asked to sign '"<<signQName<<"'|"<<DNSRecordContent::NumberToType(signQType)<<", "<<toSign.size()<<" records\n";
241
242 RRSIGRecordContent rrc;
243 if(toSign.empty())
244 return;
245
246 for(int ksk = 0; ksk < 2; ++ksk) {
e0d84497 247 if(getRRSIGForRRSET(dk, wildcardname.empty() ? signQName : wildcardname, signQType, signTTL, toSign, rrc, ksk) < 0) {
f7bcc763
BH
248 cerr<<"Error signing a record!"<<endl;
249 return;
250 }
251
252 pw.startRecord(signQName, QType::RRSIG, 3600, 1,
253 signQType==QType::DNSKEY ? DNSPacketWriter:: ANSWER : signPlace);
254 rrc.toPacket(pw);
255
256 pw.commit();
257 if(signQType != QType::DNSKEY)
258 break;
259 }
260
261 toSign.clear();
262}
263
104f67e9
BH
264pthread_mutex_t g_rrsigs_lock = PTHREAD_MUTEX_INITIALIZER;
265
f7bcc763
BH
266map<pair<string, uint16_t>, RRSIGRecordContent> g_rrsigs;
267
e0d84497 268void fillOutRRSIG(DNSSECKeeper& dk, const std::string& signQName, RRSIGRecordContent& rrc, const std::string& hash, vector<shared_ptr<DNSRecordContent> >& toSign, bool withKSK)
f7bcc763
BH
269{
270 RSAContext rc;
271
e0d84497 272 DNSKEYRecordContent drc=getDNSKEYFor(dk, rrc.d_signer, withKSK, &rc);
f7bcc763
BH
273 rrc.d_tag = drc.getTag();
274 rrc.d_algorithm = drc.d_algorithm;
104f67e9
BH
275
276 {
277 Lock l(&g_rrsigs_lock);
278 if(g_rrsigs.count(make_pair(hash, rrc.d_tag))) {
279 // cerr<<"RRSIG cache hit !"<<endl;
280 rrc = g_rrsigs[make_pair(hash, rrc.d_tag)];
281 return;
282 }
f7bcc763
BH
283 }
284
285 string realhash=getSHA1HashForRRSET(signQName, rrc, toSign);
286
287 unsigned char signature[mpi_size(&rc.getContext().N)];
288
289 int ret=rsa_pkcs1_sign(&rc.getContext(), RSA_PRIVATE, SIG_RSA_SHA1, 20, (unsigned char*) realhash.c_str(), signature);
290
291 if(ret!=0) {
292 cerr<<"signing returned: "<<ret<<endl;
293 exit(1);
294 }
295
296 rrc.d_signature.assign((char*)signature, sizeof(signature));
297
104f67e9 298 Lock l(&g_rrsigs_lock);
f7bcc763 299 g_rrsigs[make_pair(hash, rrc.d_tag)] = rrc;
f7bcc763 300}