File: validate.hh

package info (click to toggle)
pdns-recursor 5.3.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 11,116 kB
  • sloc: cpp: 109,650; javascript: 20,651; python: 5,657; sh: 5,094; makefile: 780; ansic: 582; xml: 37
file content (143 lines) | stat: -rw-r--r-- 6,742 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
 * This file is part of PowerDNS or dnsdist.
 * Copyright -- PowerDNS.COM B.V. and its contributors
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * In addition, for the avoidance of any doubt, permission is granted to
 * link this program with OpenSSL and to (re)distribute the binaries
 * produced as the result of such linking.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#pragma once

#include "dnsparser.hh"
#include "dnsname.hh"
#include <vector>
#include "namespaces.hh"
#include "dnsrecords.hh"
#include "dnssecinfra.hh"
#include "logger.hh"

extern uint32_t g_signatureInceptionSkew;
extern uint16_t g_maxNSEC3Iterations;
extern uint16_t g_maxRRSIGsPerRecordToConsider;
extern uint16_t g_maxNSEC3sPerRecordToConsider;
extern uint16_t g_maxDNSKEYsToConsider;
extern uint16_t g_maxDSsToConsider;

// 4033 5
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 };
const std::string& vStateToString(vState state);
inline bool vStateIsBogus(vState state)
{
  return state >= vState::BogusNoValidDNSKEY;
}

// NSEC(3) results
enum class dState : uint8_t { NODENIAL, INCONCLUSIVE, NXDOMAIN, NXQTYPE, ENT, INSECURE, OPTOUT};

std::ostream& operator<<(std::ostream &, vState);
std::ostream& operator<<(std::ostream &, dState);

class DNSRecordOracle
{
public:
  virtual ~DNSRecordOracle() = default;
  DNSRecordOracle(const DNSRecordOracle&) = default;
  DNSRecordOracle(DNSRecordOracle&&) = default;
  DNSRecordOracle& operator=(const DNSRecordOracle&) = default;
  DNSRecordOracle& operator=(DNSRecordOracle&&) = default;
  virtual std::vector<DNSRecord> get(const DNSName& qname, uint16_t qtype) = 0;
};


struct ContentSigPair
{
  sortedRecords_t records;
  vector<shared_ptr<const RRSIGRecordContent>> signatures;
  // ponder adding a validate method that accepts a key
};
using cspmap_t = map<pair<DNSName, uint16_t>, ContentSigPair>;
using dsset_t = std::set<DSRecordContent>;

struct sharedDNSKeyRecordContentCompare
{
  bool operator() (const shared_ptr<const DNSKEYRecordContent>& lhs, const shared_ptr<const DNSKEYRecordContent>& rhs) const
  {
    return *lhs < *rhs;
  }
};

using skeyset_t = set<shared_ptr<const DNSKEYRecordContent>, sharedDNSKeyRecordContentCompare>;

namespace pdns::validation
{
using Nsec3HashesCache = std::map<std::tuple<DNSName, std::string, uint16_t>, std::string>;

struct ValidationContext
{
  Nsec3HashesCache d_nsec3Cache;
  unsigned int d_validationsCounter{0};
  unsigned int d_nsec3IterationsRemainingQuota{0};
  bool d_limitHit{false};
};

class TooManySEC3IterationsException : public std::runtime_error
{
public:
  TooManySEC3IterationsException(): std::runtime_error("Too many NSEC3 hash computations per query")
  {
  }
};

}

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);
bool isCoveredByNSEC(const DNSName& name, const DNSName& begin, const DNSName& next);
bool isCoveredByNSEC3Hash(const std::string& hash, const std::string& beginHash, const std::string& nextHash);
bool isCoveredByNSEC3Hash(const DNSName& name, const DNSName& beginHash, const DNSName& nextHash);
bool getTrustAnchor(const map<DNSName,dsset_t>& anchors, const DNSName& zone, dsset_t &res);
bool haveNegativeTrustAnchor(const map<DNSName,std::string>& negAnchors, const DNSName& zone, std::string& reason);
vState validateDNSKeysAgainstDS(time_t now, const DNSName& zone, const dsset_t& dsset, const skeyset_t& tkeys, const sortedRecords_t& toSign, const vector<shared_ptr<const RRSIGRecordContent> >& sigs, skeyset_t& validkeys, const OptLog&, pdns::validation::ValidationContext& context);
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);
bool isSupportedDS(const DSRecordContent& dsRecordContent, const OptLog&);
DNSName getSigner(const std::vector<std::shared_ptr<const RRSIGRecordContent> >& signatures);
bool denialProvesNoDelegation(const DNSName& zone, const std::vector<DNSRecord>& dsrecords, pdns::validation::ValidationContext& context);
bool isRRSIGNotExpired(time_t now, const RRSIGRecordContent& sig);
bool isRRSIGIncepted(time_t now, const RRSIGRecordContent& sig);
bool isWildcardExpanded(unsigned int labelCount, const RRSIGRecordContent& sign);
bool isWildcardExpandedOntoItself(const DNSName& owner, unsigned int labelCount, const RRSIGRecordContent& sign);
void updateDNSSECValidationState(vState& state, vState stateUpdate);

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&);

bool isNSEC3AncestorDelegation(const DNSName& signer, const DNSName& owner, const NSEC3RecordContent& nsec3);
DNSName getNSECOwnerName(const DNSName& initialOwner, const std::vector<std::shared_ptr<const RRSIGRecordContent> >& signatures);
DNSName getClosestEncloserFromNSEC(const DNSName& name, const DNSName& owner, const DNSName& next);
[[nodiscard]] uint64_t getNSEC3DenialProofWorstCaseIterationsCount(uint8_t maxLabels, uint16_t iterations, size_t saltLength);
[[nodiscard]] std::string getHashFromNSEC3(const DNSName& qname, uint16_t iterations, const std::string& salt, pdns::validation::ValidationContext& context);

template <typename NSEC> bool isTypeDenied(const NSEC& nsec, const QType& type)
{
  if (nsec.isSet(type.getCode())) {
    return false;
  }

  /* RFC 6840 section 4.3 */
  if (nsec.isSet(QType::CNAME)) {
    return false;
  }

  return true;
}