Index: net/base/dnssec_chain_verifier.cc |
diff --git a/net/base/dnssec_chain_verifier.cc b/net/base/dnssec_chain_verifier.cc |
index 5104545b6e5639a0878d46e4bd9b7d704165501b..4ea79b358c983e33cc29b95c5a0005ecaa4fbefa 100644 |
--- a/net/base/dnssec_chain_verifier.cc |
+++ b/net/base/dnssec_chain_verifier.cc |
@@ -543,6 +543,20 @@ DNSSECChainVerifier::Error DNSSECChainVerifier::EnterZone( |
return OK; |
} |
+// IsValidTerminalRRType returns true if the given RR type is one that we |
+// accept as the terminal record in a DNSSEC chain. |
+bool DNSSECChainVerifier::IsValidTerminalRRType(uint16 rrtype) { |
+ switch (rrtype) { |
+ case kDNS_CAA: |
+ case kDNS_CERT: |
+ case kDNS_TLSA: |
+ case kDNS_TXT: |
+ return true; |
+ } |
+ |
+ return false; |
+} |
+ |
// LeaveZone transitions out of the current zone, either by following DS |
// records to validate the entry key of the next zone, or because the final |
// resource records are given. |
@@ -562,7 +576,7 @@ DNSSECChainVerifier::Error DNSSECChainVerifier::LeaveZone( |
if (rrtype == kDNS_DS) { |
err = ReadDSSet(&rrdatas, *next_name); |
- } else if (rrtype == kDNS_CERT || rrtype == kDNS_TXT || rrtype == kDNS_CAA) { |
+ } else if (IsValidTerminalRRType(rrtype)) { |
err = ReadGenericRRs(&rrdatas); |
} else if (rrtype == kDNS_CNAME) { |
err = ReadCNAME(&rrdatas); |
@@ -582,7 +596,7 @@ DNSSECChainVerifier::Error DNSSECChainVerifier::LeaveZone( |
// 'closer' to the target than the current zone. |
if (MatchingLabels(target_, *next_name) <= current_zone_->matching_labels) |
return OFF_COURSE; |
- } else if (rrtype == kDNS_CERT || rrtype == kDNS_TXT || rrtype == kDNS_CAA) { |
+ } else if (IsValidTerminalRRType(rrtype)) { |
// If this is the final entry in the chain then the name must match target_ |
if (next_name->size() != target_.size() || |
memcmp(next_name->data(), target_.data(), target_.size())) { |
@@ -744,6 +758,7 @@ struct CAAHashFunctionOID { |
// The values here are taken from NSS's freebl/hasht.h. Sadly, we cannot |
// include it because it pulls in #defines that conflict with Chromium headers. |
// However, these values are part of NSS's public API and so are stable. |
+static const int kHashNone = 0; |
static const int kHashSHA256 = 4; |
static const int kHashSHA384 = 5; |
static const int kHashSHA512 = 6; |
@@ -916,4 +931,65 @@ DnsCAARecord::ParseResult DnsCAARecord::Parse( |
return SUCCESS; |
} |
+void DnsTLSARecord::Parse( |
+ const std::vector<base::StringPiece>& rrdatas, |
+ std::vector<DnsTLSARecord::Match>* output) { |
+ // see https://tools.ietf.org/html/rfc6698#section-2.1 |
+ output->clear(); |
+ |
+ for (std::vector<base::StringPiece>::const_iterator |
+ ii = rrdatas.begin(); ii != rrdatas.end(); ++ii) { |
+ base::StringPiece i = *ii; |
+ |
+ if (i.size() < 3) |
+ continue; |
+ |
+ const uint8 cert_usage = i[0]; |
+ const uint8 selector = i[1]; |
+ const uint8 match_type = i[2]; |
+ i.remove_prefix(3); |
+ |
+ if (cert_usage != 3) { |
+ // Type 3 is a "domain issued certificate" - i.e. a certificate (or |
+ // public key) which is granted authority by the TLSA record. |
+ continue; |
+ } |
+ |
+ Match match; |
+ |
+ switch (selector) { |
+ case 0: |
+ match.target = Match::CERTIFICATE; |
+ break; |
+ case 1: |
+ match.target = Match::SUBJECT_PUBLIC_KEY_INFO; |
+ break; |
+ default: |
+ continue; |
+ } |
+ |
+ switch (match_type) { |
+ case 0: |
+ match.algorithm = kHashNone; |
+ break; |
+ case 1: |
+ match.algorithm = kHashSHA256; |
+ break; |
+ case 2: |
+ match.algorithm = kHashSHA512; |
+ break; |
+ default: |
+ continue; |
+ } |
+ |
+ if (match.algorithm != kHashNone && |
+ i.size() != DigestLength(match.algorithm)) { |
+ continue; |
+ } |
+ |
+ match.data = i.as_string(); |
+ output->push_back(match); |
+ } |
+} |
+ |
} // namespace net |