]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnssecsigner.cc
Standardize license text in all PDNS files
[thirdparty/pdns.git] / pdns / dnssecsigner.cc
CommitLineData
882358c8 1/*
12471842
PL
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
870a0fe4
AT
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
882358c8
BH
25#include "dnssecinfra.hh"
26#include "namespaces.hh"
fa8fd4d2 27
8d9f38f2 28#include "md5.hh"
882358c8 29#include "dnsseckeeper.hh"
ff1040bf 30#include "dns_random.hh"
882358c8 31#include "lock.hh"
bba84134 32#include "arguments.hh"
c681ff64 33#include "statbag.hh"
34extern StatBag S;
882358c8 35
d3e7090c 36/* this is where the RRSIGs begin, keys are retrieved,
882358c8 37 but the actual signing happens in fillOutRRSIG */
675fa24c 38int getRRSIGsForRRSET(DNSSECKeeper& dk, const DNSName& signer, const DNSName signQName, uint16_t signQType, uint32_t signTTL,
8a95b04c 39 vector<shared_ptr<DNSRecordContent> >& toSign, vector<RRSIGRecordContent>& rrcs)
882358c8
BH
40{
41 if(toSign.empty())
42 return -1;
b61e407d 43 uint32_t startOfWeek = getStartOfWeek();
882358c8
BH
44 RRSIGRecordContent rrc;
45 rrc.d_type=signQType;
46
8aa5a28c 47 rrc.d_labels=signQName.countLabels()-signQName.isWildcard();
882358c8 48 rrc.d_originalttl=signTTL;
b61e407d
KM
49 rrc.d_siginception=startOfWeek - 7*86400; // XXX should come from zone metadata
50 rrc.d_sigexpire=startOfWeek + 14*86400;
675fa24c 51 rrc.d_signer = signer;
882358c8 52 rrc.d_tag = 0;
7dc95f99 53
b6bd795c 54 DNSSECKeeper::keyset_t keys = dk.getKeys(signer);
7dc95f99 55
b6bd795c 56 for(DNSSECKeeper::keyset_t::value_type& keymeta : keys) {
7dc95f99 57 if(!keymeta.second.active)
882358c8 58 continue;
8a95b04c 59
b6bd795c
PL
60 if((signQType == QType::DNSKEY && keymeta.second.keyType == DNSSECKeeper::ZSK) ||
61 (signQType != QType::DNSKEY && keymeta.second.keyType == DNSSECKeeper::KSK)) {
62 continue;
7dc95f99
KM
63 }
64
b6bd795c 65 fillOutRRSIG(keymeta.first, signQName, rrc, toSign);
882358c8
BH
66 rrcs.push_back(rrc);
67 }
68 return 0;
69}
70
71// this is the entrypoint from DNSPacket
675fa24c 72void addSignature(DNSSECKeeper& dk, UeberBackend& db, const DNSName& signer, const DNSName signQName, const DNSName& wildcardname, uint16_t signQType,
e693ff5a 73 uint32_t signTTL, DNSResourceRecord::Place signPlace,
794c2f92 74 vector<shared_ptr<DNSRecordContent> >& toSign, vector<DNSResourceRecord>& outsigned, uint32_t origTTL)
882358c8 75{
51a3a4d4 76 //cerr<<"Asked to sign '"<<signQName<<"'|"<<DNSRecordContent::NumberToType(signQType)<<", "<<toSign.size()<<" records\n";
882358c8
BH
77 if(toSign.empty())
78 return;
d3e7090c
BH
79 vector<RRSIGRecordContent> rrcs;
80 if(dk.isPresigned(signer)) {
51a3a4d4 81 //cerr<<"Doing presignatures"<<endl;
794c2f92 82 dk.getPreRRSIGs(db, signer, signQName, wildcardname, QType(signQType), signPlace, outsigned, origTTL); // does it all
d3e7090c 83 }
6b35b541 84 else {
675fa24c 85 if(getRRSIGsForRRSET(dk, signer, wildcardname.countLabels() ? wildcardname : signQName, signQType, signTTL, toSign, rrcs) < 0) {
6b35b541
BH
86 // cerr<<"Error signing a record!"<<endl;
87 return;
88 }
e02d0a59 89
6b35b541
BH
90 DNSResourceRecord rr;
91 rr.qname=signQName;
92 rr.qtype=QType::RRSIG;
794c2f92
PD
93 if(origTTL)
94 rr.ttl=origTTL;
95 else
96 rr.ttl=signTTL;
6b35b541 97 rr.auth=false;
e693ff5a 98 rr.d_place = signPlace;
ef7cd021 99 for(RRSIGRecordContent& rrc : rrcs) {
6b35b541
BH
100 rr.content = rrc.getZoneRepresentation();
101 outsigned.push_back(rr);
102 }
882358c8 103 }
882358c8
BH
104 toSign.clear();
105}
106
ccc3f9ed
BH
107static pthread_rwlock_t g_signatures_lock = PTHREAD_RWLOCK_INITIALIZER;
108typedef map<pair<string, string>, string> signaturecache_t;
109static signaturecache_t g_signatures;
110static int g_cacheweekno;
882358c8 111
c681ff64 112AtomicCounter* g_signatureCount;
113
e903706d 114uint64_t signatureCacheSize(const std::string& str)
115{
116 ReadLock l(&g_signatures_lock);
117 return g_signatures.size();
118}
119
561434a6 120void fillOutRRSIG(DNSSECPrivateKey& dpk, const DNSName& signQName, RRSIGRecordContent& rrc, vector<shared_ptr<DNSRecordContent> >& toSign)
882358c8 121{
c681ff64 122 if(!g_signatureCount)
123 g_signatureCount = S.getPointer("signatures");
124
699e6e37 125 DNSKEYRecordContent drc = dpk.getDNSKEY();
8d9f38f2 126 const DNSCryptoKeyEngine* rc = dpk.getKey();
882358c8
BH
127 rrc.d_tag = drc.getTag();
128 rrc.d_algorithm = drc.d_algorithm;
8d9f38f2 129
f309dacd 130 string msg=getMessageForRRSET(signQName, rrc, toSign); // this is what we will hash & sign
ccc3f9ed 131 pair<string, string> lookup(rc->getPubKeyHash(), pdns_md5sum(msg)); // this hash is a memory saving exercise
6e015d20 132
bec14a20
BH
133 bool doCache=1;
134 if(doCache)
882358c8 135 {
ccc3f9ed
BH
136 ReadLock l(&g_signatures_lock);
137 signaturecache_t::const_iterator iter = g_signatures.find(lookup);
138 if(iter != g_signatures.end()) {
139 rrc.d_signature=iter->second;
882358c8
BH
140 return;
141 }
e125fc69 142 // else cerr<<"Miss!"<<endl;
882358c8
BH
143 }
144
f309dacd 145 rrc.d_signature = rc->sign(msg);
c681ff64 146 (*g_signatureCount)++;
bec14a20 147 if(doCache) {
ff1040bf 148 /* we add some jitter here so not all your slaves start pruning their caches at the very same millisecond */
222efdc0 149 int weekno = (time(0) - dns_random(3600)) / (86400*7); // we just spent milliseconds doing a signature, microsecond more won't kill us
bba84134 150 const static int maxcachesize=::arg().asNum("max-signature-cache-entries", INT_MAX);
a732a4c9 151
152 WriteLock l(&g_signatures_lock);
bba84134
KM
153 if(g_cacheweekno < weekno || g_signatures.size() >= (uint) maxcachesize) { // blunt but effective (C) Habbie, mind04
154 L<<Logger::Warning<<"Cleared signature cache."<<endl;
ccc3f9ed
BH
155 g_signatures.clear();
156 g_cacheweekno = weekno;
157 }
bec14a20
BH
158 g_signatures[lookup] = rrc.d_signature;
159 }
882358c8 160}
e02d0a59
BH
161
162static bool rrsigncomp(const DNSResourceRecord& a, const DNSResourceRecord& b)
163{
dca357a1 164 return tie(a.d_place, a.qtype) < tie(b.d_place, b.qtype);
e02d0a59
BH
165}
166
675fa24c 167static bool getBestAuthFromSet(const set<DNSName>& authSet, const DNSName& name, DNSName& auth)
8d3cbffa 168{
675fa24c
PD
169 auth.trimToLabels(0);
170 DNSName sname(name);
8d3cbffa
BH
171 do {
172 if(authSet.find(sname) != authSet.end()) {
173 auth = sname;
174 return true;
175 }
176 }
675fa24c 177 while(sname.chopOff());
8d3cbffa
BH
178
179 return false;
180}
181
675fa24c 182void addRRSigs(DNSSECKeeper& dk, UeberBackend& db, const set<DNSName>& authSet, vector<DNSResourceRecord>& rrs)
e02d0a59 183{
e02d0a59
BH
184 stable_sort(rrs.begin(), rrs.end(), rrsigncomp);
185
675fa24c 186 DNSName signQName, wildcardQName;
e02d0a59
BH
187 uint16_t signQType=0;
188 uint32_t signTTL=0;
794c2f92 189 uint32_t origTTL=0;
e02d0a59 190
e693ff5a 191 DNSResourceRecord::Place signPlace=DNSResourceRecord::ANSWER;
e02d0a59
BH
192 vector<shared_ptr<DNSRecordContent> > toSign;
193
194 vector<DNSResourceRecord> signedRecords;
d42896fb 195 signedRecords.reserve(rrs.size()*1.5);
196 // cout<<rrs.size()<<", "<<sizeof(DNSResourceRecord)<<endl;
675fa24c 197 DNSName signer;
e02d0a59 198 for(vector<DNSResourceRecord>::const_iterator pos = rrs.begin(); pos != rrs.end(); ++pos) {
e02d0a59 199 if(pos != rrs.begin() && (signQType != pos->qtype.getCode() || signQName != pos->qname)) {
8d3cbffa 200 if(getBestAuthFromSet(authSet, signQName, signer))
794c2f92 201 addSignature(dk, db, signer, signQName, wildcardQName, signQType, signTTL, signPlace, toSign, signedRecords, origTTL);
e02d0a59 202 }
8e9b7d99 203 signedRecords.push_back(*pos);
d42896fb 204 signQName= pos->qname.makeLowerCase();
e1a9ab9f 205 if(!pos->wildcardname.empty())
d42896fb 206 wildcardQName = pos->wildcardname.makeLowerCase();
07338ade
KM
207 else
208 wildcardQName.clear();
e02d0a59 209 signQType = pos ->qtype.getCode();
794c2f92
PD
210 if(pos->signttl)
211 signTTL = pos->signttl;
212 else
213 signTTL = pos->ttl;
214 origTTL = pos->ttl;
e693ff5a 215 signPlace = pos->d_place;
e02d0a59 216 if(pos->auth || pos->qtype.getCode() == QType::DS) {
6b35b541 217 string content = pos->content;
e02d0a59
BH
218 if(!pos->content.empty() && pos->qtype.getCode()==QType::TXT && pos->content[0]!='"') {
219 content="\""+pos->content+"\"";
220 }
221 if(pos->content.empty()) // empty contents confuse the MOADNS setup
222 content=".";
223
224 shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(pos->qtype.getCode(), 1, content));
225 toSign.push_back(drc);
226 }
227 }
8d3cbffa 228 if(getBestAuthFromSet(authSet, signQName, signer))
794c2f92 229 addSignature(dk, db, signer, signQName, wildcardQName, signQType, signTTL, signPlace, toSign, signedRecords, origTTL);
e02d0a59
BH
230 rrs.swap(signedRecords);
231}