]>
Commit | Line | Data |
---|---|---|
12471842 PL |
1 | /* |
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 | */ | |
243f4780 | 22 | #pragma once |
23 | ||
24 | #include "dnsparser.hh" | |
25 | #include "dnsname.hh" | |
26 | #include <vector> | |
27 | #include "namespaces.hh" | |
28 | #include "dnsrecords.hh" | |
c1e7b833 | 29 | #include "dnssecinfra.hh" |
10971f78 OM |
30 | #include "logger.hh" |
31 | ||
9a3ab3e4 | 32 | extern time_t g_signatureInceptionSkew; |
d377bb54 | 33 | extern uint16_t g_maxNSEC3Iterations; |
15e973d6 OM |
34 | extern uint16_t g_maxRRSIGsPerRecordToConsider; |
35 | extern uint16_t g_maxNSEC3sPerRecordToConsider; | |
36 | extern uint16_t g_maxDNSKEYsToConsider; | |
37 | extern uint16_t g_maxDSsToConsider; | |
3e9c6c0a | 38 | |
243f4780 | 39 | // 4033 5 |
fecac3ba | 40 | enum class vState : uint8_t { Indeterminate, Insecure, Secure, NTA, TA, BogusNoValidDNSKEY, BogusInvalidDenial, BogusUnableToGetDSs, BogusUnableToGetDNSKEYs, BogusSelfSignedDS, BogusNoRRSIG, BogusNoValidRRSIG, BogusMissingNegativeIndication, BogusSignatureNotYetValid, BogusSignatureExpired, BogusUnsupportedDNSKEYAlgo, BogusUnsupportedDSDigestType, BogusNoZoneKeyBitSet, BogusRevokedDNSKEY, BogusInvalidDNSKEYProtocol }; |
98307d0f | 41 | const std::string& vStateToString(vState state); |
fd870915 RG |
42 | inline bool vStateIsBogus(vState state) |
43 | { | |
44 | return state >= vState::BogusNoValidDNSKEY; | |
45 | } | |
243f4780 | 46 | |
47 | // NSEC(3) results | |
cd4beb37 | 48 | enum class dState : uint8_t { NODENIAL, INCONCLUSIVE, NXDOMAIN, NXQTYPE, ENT, INSECURE, OPTOUT}; |
243f4780 | 49 | |
7ada1188 OM |
50 | std::ostream& operator<<(std::ostream &, vState); |
51 | std::ostream& operator<<(std::ostream &, dState); | |
9df058c4 | 52 | |
243f4780 | 53 | class DNSRecordOracle |
54 | { | |
55 | public: | |
7ada1188 OM |
56 | virtual ~DNSRecordOracle() = default; |
57 | DNSRecordOracle(const DNSRecordOracle&) = default; | |
58 | DNSRecordOracle(DNSRecordOracle&&) = default; | |
59 | DNSRecordOracle& operator=(const DNSRecordOracle&) = default; | |
60 | DNSRecordOracle& operator=(DNSRecordOracle&&) = default; | |
61 | virtual std::vector<DNSRecord> get(const DNSName& qname, uint16_t qtype) = 0; | |
243f4780 | 62 | }; |
63 | ||
64 | ||
65 | struct ContentSigPair | |
66 | { | |
c1e7b833 | 67 | sortedRecords_t records; |
d06dcda4 | 68 | vector<shared_ptr<const RRSIGRecordContent>> signatures; |
243f4780 | 69 | // ponder adding a validate method that accepts a key |
70 | }; | |
7ada1188 OM |
71 | using cspmap_t = map<pair<DNSName, uint16_t>, ContentSigPair>; |
72 | using dsmap_t = std::set<DSRecordContent>; | |
243f4780 | 73 | |
4d2be65d RG |
74 | struct sharedDNSKeyRecordContentCompare |
75 | { | |
7ada1188 | 76 | bool operator() (const shared_ptr<const DNSKEYRecordContent>& lhs, const shared_ptr<const DNSKEYRecordContent>& rhs) const |
4d2be65d | 77 | { |
7ada1188 | 78 | return *lhs < *rhs; |
4d2be65d RG |
79 | } |
80 | }; | |
81 | ||
7ada1188 | 82 | using skeyset_t = set<shared_ptr<const DNSKEYRecordContent>, sharedDNSKeyRecordContentCompare>; |
4d2be65d | 83 | |
15e973d6 OM |
84 | namespace pdns::validation |
85 | { | |
86 | using Nsec3HashesCache = std::map<std::tuple<DNSName, std::string, uint16_t>, std::string>; | |
87 | ||
88 | struct ValidationContext | |
89 | { | |
90 | Nsec3HashesCache d_nsec3Cache; | |
91 | unsigned int d_validationsCounter{0}; | |
92 | unsigned int d_nsec3IterationsRemainingQuota{0}; | |
9d4a01ff | 93 | bool d_limitHit{false}; |
15e973d6 OM |
94 | }; |
95 | ||
96 | class TooManySEC3IterationsException : public std::runtime_error | |
97 | { | |
98 | public: | |
99 | TooManySEC3IterationsException(): std::runtime_error("Too many NSEC3 hash computations per query") | |
100 | { | |
101 | } | |
102 | }; | |
103 | ||
104 | } | |
25f5783a | 105 | |
15e973d6 | 106 | vState validateWithKeySet(time_t now, const DNSName& name, const sortedRecords_t& toSign, const vector<shared_ptr<const RRSIGRecordContent> >& signatures, const skeyset_t& keys, const OptLog& log, pdns::validation::ValidationContext& context, bool validateAllSigs=true); |
25f5783a | 107 | bool isCoveredByNSEC(const DNSName& name, const DNSName& begin, const DNSName& next); |
7ada1188 OM |
108 | bool isCoveredByNSEC3Hash(const std::string& hash, const std::string& beginHash, const std::string& nextHash); |
109 | bool isCoveredByNSEC3Hash(const DNSName& name, const DNSName& beginHash, const DNSName& nextHash); | |
4d2be65d RG |
110 | bool getTrustAnchor(const map<DNSName,dsmap_t>& anchors, const DNSName& zone, dsmap_t &res); |
111 | bool haveNegativeTrustAnchor(const map<DNSName,std::string>& negAnchors, const DNSName& zone, std::string& reason); | |
15e973d6 OM |
112 | vState validateDNSKeysAgainstDS(time_t now, const DNSName& zone, const dsmap_t& dsmap, const skeyset_t& tkeys, const sortedRecords_t& toSign, const vector<shared_ptr<const RRSIGRecordContent> >& sigs, skeyset_t& validkeys, const OptLog&, pdns::validation::ValidationContext& context); |
113 | dState getDenial(const cspmap_t &validrrsets, const DNSName& qname, uint16_t qtype, bool referralToUnsigned, bool wantsNoDataProof, pdns::validation::ValidationContext& context, const OptLog& log = std::nullopt, bool needWildcardProof=true, unsigned int wildcardLabelsCount=0); | |
7ada1188 | 114 | bool isSupportedDS(const DSRecordContent& dsRecordContent, const OptLog&); |
d06dcda4 | 115 | DNSName getSigner(const std::vector<std::shared_ptr<const RRSIGRecordContent> >& signatures); |
15e973d6 | 116 | bool denialProvesNoDelegation(const DNSName& zone, const std::vector<DNSRecord>& dsrecords, pdns::validation::ValidationContext& context); |
7ada1188 OM |
117 | bool isRRSIGNotExpired(time_t now, const RRSIGRecordContent& sig); |
118 | bool isRRSIGIncepted(time_t now, const RRSIGRecordContent& sig); | |
03e5e4cb RG |
119 | bool isWildcardExpanded(unsigned int labelCount, const RRSIGRecordContent& sign); |
120 | bool isWildcardExpandedOntoItself(const DNSName& owner, unsigned int labelCount, const RRSIGRecordContent& sign); | |
7ada1188 | 121 | void updateDNSSECValidationState(vState& state, vState stateUpdate); |
25f5783a | 122 | |
03e5e4cb | 123 | dState matchesNSEC(const DNSName& name, uint16_t qtype, const DNSName& nsecOwner, const NSECRecordContent& nsec, const std::vector<std::shared_ptr<const RRSIGRecordContent>>& signatures, const OptLog&); |
25f5783a | 124 | |
03e5e4cb | 125 | bool isNSEC3AncestorDelegation(const DNSName& signer, const DNSName& owner, const NSEC3RecordContent& nsec3); |
d06dcda4 | 126 | DNSName getNSECOwnerName(const DNSName& initialOwner, const std::vector<std::shared_ptr<const RRSIGRecordContent> >& signatures); |
57fe2038 | 127 | DNSName getClosestEncloserFromNSEC(const DNSName& name, const DNSName& owner, const DNSName& next); |
15e973d6 OM |
128 | [[nodiscard]] uint64_t getNSEC3DenialProofWorstCaseIterationsCount(uint8_t maxLabels, uint16_t iterations, size_t saltLength); |
129 | [[nodiscard]] std::string getHashFromNSEC3(const DNSName& qname, uint16_t iterations, const std::string& salt, pdns::validation::ValidationContext& context); | |
cd4beb37 RG |
130 | |
131 | template <typename NSEC> bool isTypeDenied(const NSEC& nsec, const QType& type) | |
132 | { | |
03e5e4cb | 133 | if (nsec.isSet(type.getCode())) { |
cd4beb37 RG |
134 | return false; |
135 | } | |
136 | ||
137 | /* RFC 6840 section 4.3 */ | |
03e5e4cb | 138 | if (nsec.isSet(QType::CNAME)) { |
cd4beb37 RG |
139 | return false; |
140 | } | |
141 | ||
cd4beb37 RG |
142 | return true; |
143 | } |