OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This file includes code SSLClientSocketNSS::DoVerifyCertComplete() derived | 5 // This file includes code SSLClientSocketNSS::DoVerifyCertComplete() derived |
6 // from AuthCertificateCallback() in | 6 // from AuthCertificateCallback() in |
7 // mozilla/security/manager/ssl/src/nsNSSCallbacks.cpp. | 7 // mozilla/security/manager/ssl/src/nsNSSCallbacks.cpp. |
8 | 8 |
9 /* ***** BEGIN LICENSE BLOCK ***** | 9 /* ***** BEGIN LICENSE BLOCK ***** |
10 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 | 10 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
272 DNSVR_SUCCESS, // the cert is immediately acceptable. | 272 DNSVR_SUCCESS, // the cert is immediately acceptable. |
273 DNSVR_FAILURE, // the cert is unconditionally rejected. | 273 DNSVR_FAILURE, // the cert is unconditionally rejected. |
274 DNSVR_CONTINUE, // perform CA validation as usual. | 274 DNSVR_CONTINUE, // perform CA validation as usual. |
275 }; | 275 }; |
276 | 276 |
277 // VerifyCAARecords processes DNSSEC validated RRDATA for a number of DNS CAA | 277 // VerifyCAARecords processes DNSSEC validated RRDATA for a number of DNS CAA |
278 // records and checks them against the given chain. | 278 // records and checks them against the given chain. |
279 // server_cert_nss: the server's leaf certificate. | 279 // server_cert_nss: the server's leaf certificate. |
280 // rrdatas: the CAA records for the current domain. | 280 // rrdatas: the CAA records for the current domain. |
281 // port: the TCP port number that we connected to. | 281 // port: the TCP port number that we connected to. |
| 282 // TODO(agl): remove once DANE support has been released. |
282 DNSValidationResult VerifyCAARecords( | 283 DNSValidationResult VerifyCAARecords( |
283 CERTCertificate* server_cert_nss, | 284 CERTCertificate* server_cert_nss, |
284 const std::vector<base::StringPiece>& rrdatas, | 285 const std::vector<base::StringPiece>& rrdatas, |
285 uint16 port) { | 286 uint16 port) { |
286 DnsCAARecord::Policy policy; | 287 DnsCAARecord::Policy policy; |
287 const DnsCAARecord::ParseResult r = DnsCAARecord::Parse(rrdatas, &policy); | 288 const DnsCAARecord::ParseResult r = DnsCAARecord::Parse(rrdatas, &policy); |
288 if (r == DnsCAARecord::SYNTAX_ERROR || r == DnsCAARecord::UNKNOWN_CRITICAL) | 289 if (r == DnsCAARecord::SYNTAX_ERROR || r == DnsCAARecord::UNKNOWN_CRITICAL) |
289 return DNSVR_FAILURE; | 290 return DNSVR_FAILURE; |
290 if (r == DnsCAARecord::DISCARD) | 291 if (r == DnsCAARecord::DISCARD) |
291 return DNSVR_CONTINUE; | 292 return DNSVR_CONTINUE; |
(...skipping 25 matching lines...) Expand all Loading... |
317 return DNSVR_SUCCESS; | 318 return DNSVR_SUCCESS; |
318 } | 319 } |
319 } | 320 } |
320 } | 321 } |
321 | 322 |
322 // If a CAA record was found, but nothing matched, then we reject the | 323 // If a CAA record was found, but nothing matched, then we reject the |
323 // certificate. | 324 // certificate. |
324 return DNSVR_FAILURE; | 325 return DNSVR_FAILURE; |
325 } | 326 } |
326 | 327 |
| 328 // VerifyTLSARecords processes DNSSEC validated RRDATA for a number of DNS TLSA |
| 329 // records and checks them against the given chain. |
| 330 // server_cert_nss: the server's leaf certificate. |
| 331 // rrdatas: the TLSA records for the current domain. |
| 332 DNSValidationResult VerifyTLSARecords( |
| 333 CERTCertificate* server_cert_nss, |
| 334 const std::vector<base::StringPiece>& rrdatas) { |
| 335 std::vector<DnsTLSARecord::Match> matches; |
| 336 DnsTLSARecord::Parse(rrdatas, &matches); |
| 337 |
| 338 for (std::vector<DnsTLSARecord::Match>::const_iterator |
| 339 i = matches.begin(); i != matches.end(); ++i) { |
| 340 SECItem matched_data; |
| 341 switch (i->target) { |
| 342 case DnsTLSARecord::Match::CERTIFICATE: |
| 343 matched_data = server_cert_nss->derCert; |
| 344 break; |
| 345 case DnsTLSARecord::Match::SUBJECT_PUBLIC_KEY_INFO: |
| 346 matched_data = server_cert_nss->derPublicKey; |
| 347 break; |
| 348 default: |
| 349 continue; |
| 350 } |
| 351 |
| 352 uint8 calculated_hash[HASH_LENGTH_MAX]; |
| 353 SECItem processed_data; |
| 354 if (i->algorithm == HASH_AlgNULL) { |
| 355 processed_data = matched_data; |
| 356 } else { |
| 357 SECStatus rv = HASH_HashBuf( |
| 358 static_cast<HASH_HashType>(i->algorithm), |
| 359 calculated_hash, |
| 360 matched_data.data, |
| 361 matched_data.len); |
| 362 if (rv != SECSuccess) |
| 363 continue; |
| 364 processed_data.data = calculated_hash; |
| 365 processed_data.len = i->data.size(); |
| 366 } |
| 367 |
| 368 if (processed_data.len == i->data.size() && |
| 369 memcmp(processed_data.data, i->data.data(), i->data.size()) == 0) { |
| 370 return DNSVR_SUCCESS; |
| 371 } |
| 372 } |
| 373 |
| 374 // No TLSA records matched so we reject the certificate. |
| 375 return DNSVR_FAILURE; |
| 376 } |
| 377 |
327 // CheckDNSSECChain tries to validate a DNSSEC chain embedded in | 378 // CheckDNSSECChain tries to validate a DNSSEC chain embedded in |
328 // |server_cert_nss|. It returns true iff a chain is found that proves the | 379 // |server_cert_nss|. It returns true iff a chain is found that proves the |
329 // value of a CAA record that contains a valid public key fingerprint. | 380 // value of a CAA record that contains a valid public key fingerprint. |
330 // |port| contains the TCP port number that we connected to as CAA records can | 381 // |port| contains the TCP port number that we connected to as CAA records can |
331 // be specific to a given port. | 382 // be specific to a given port. |
332 DNSValidationResult CheckDNSSECChain( | 383 DNSValidationResult CheckDNSSECChain( |
333 const std::string& hostname, | 384 const std::string& hostname, |
334 CERTCertificate* server_cert_nss, | 385 CERTCertificate* server_cert_nss, |
335 uint16 port) { | 386 uint16 port) { |
336 if (!server_cert_nss) | 387 if (!server_cert_nss) |
(...skipping 20 matching lines...) Expand all Loading... |
357 DCHECK_NE(SEC_OID_UNKNOWN, dnssec_chain_tag); | 408 DCHECK_NE(SEC_OID_UNKNOWN, dnssec_chain_tag); |
358 dnssec_chain_tag_valid = true; | 409 dnssec_chain_tag_valid = true; |
359 } | 410 } |
360 | 411 |
361 SECItem dnssec_embedded_chain; | 412 SECItem dnssec_embedded_chain; |
362 SECStatus rv = CERT_FindCertExtension(server_cert_nss, | 413 SECStatus rv = CERT_FindCertExtension(server_cert_nss, |
363 dnssec_chain_tag, &dnssec_embedded_chain); | 414 dnssec_chain_tag, &dnssec_embedded_chain); |
364 if (rv != SECSuccess) | 415 if (rv != SECSuccess) |
365 return DNSVR_CONTINUE; | 416 return DNSVR_CONTINUE; |
366 | 417 |
367 base::StringPiece chain( | 418 std::string chain( |
368 reinterpret_cast<char*>(dnssec_embedded_chain.data), | 419 reinterpret_cast<char*>(dnssec_embedded_chain.data), |
369 dnssec_embedded_chain.len); | 420 dnssec_embedded_chain.len); |
| 421 SECITEM_FreeItem(&dnssec_embedded_chain, PR_FALSE); |
370 std::string dns_hostname; | 422 std::string dns_hostname; |
371 if (!DNSDomainFromDot(hostname, &dns_hostname)) | 423 if (!DNSDomainFromDot(hostname, &dns_hostname)) |
372 return DNSVR_CONTINUE; | 424 return DNSVR_CONTINUE; |
| 425 |
373 DNSSECChainVerifier verifier(dns_hostname, chain); | 426 DNSSECChainVerifier verifier(dns_hostname, chain); |
374 DNSSECChainVerifier::Error err = verifier.Verify(); | 427 DNSSECChainVerifier::Error err = verifier.Verify(); |
| 428 bool is_tlsa = false; |
| 429 if (err == DNSSECChainVerifier::BAD_TARGET) { |
| 430 // We might have failed because this is a DANE chain, not a CAA chain. |
| 431 // DANE stores records in a subdomain of the name that includes the port |
| 432 // and protocol, i.e. _443._tcp.www.example.com. We have to construct |
| 433 // such a name for |hostname|. |
| 434 const std::string port_str = base::UintToString(port); |
| 435 char port_label_len = 1 + static_cast<char>(port_str.size()); |
| 436 const std::string tlsa_domain = |
| 437 std::string(&port_label_len, 1) + "_" + port_str + |
| 438 "\x04_tcp" + |
| 439 dns_hostname; |
| 440 |
| 441 verifier = DNSSECChainVerifier(tlsa_domain, chain); |
| 442 err = verifier.Verify(); |
| 443 is_tlsa = true; |
| 444 } |
| 445 |
375 if (err != DNSSECChainVerifier::OK) { | 446 if (err != DNSSECChainVerifier::OK) { |
376 LOG(ERROR) << "DNSSEC chain verification failed: " << err; | 447 LOG(ERROR) << "DNSSEC chain verification failed: " << err; |
377 return DNSVR_CONTINUE; | 448 return DNSVR_CONTINUE; |
378 } | 449 } |
379 | 450 |
| 451 if (is_tlsa) { |
| 452 if (verifier.rrtype() != kDNS_TLSA) |
| 453 return DNSVR_CONTINUE; |
| 454 |
| 455 return VerifyTLSARecords(server_cert_nss, verifier.rrdatas()); |
| 456 } |
| 457 |
380 if (verifier.rrtype() != kDNS_CAA) | 458 if (verifier.rrtype() != kDNS_CAA) |
381 return DNSVR_CONTINUE; | 459 return DNSVR_CONTINUE; |
382 | 460 |
383 DNSValidationResult r = VerifyCAARecords( | 461 return VerifyCAARecords(server_cert_nss, verifier.rrdatas(), port); |
384 server_cert_nss, verifier.rrdatas(), port); | |
385 SECITEM_FreeItem(&dnssec_embedded_chain, PR_FALSE); | |
386 | |
387 return r; | |
388 } | 462 } |
389 | 463 |
390 void DestroyCertificates(CERTCertificate** certs, size_t len) { | 464 void DestroyCertificates(CERTCertificate** certs, size_t len) { |
391 for (size_t i = 0; i < len; i++) | 465 for (size_t i = 0; i < len; i++) |
392 CERT_DestroyCertificate(certs[i]); | 466 CERT_DestroyCertificate(certs[i]); |
393 } | 467 } |
394 | 468 |
395 // Helper functions to make it possible to log events from within the | 469 // Helper functions to make it possible to log events from within the |
396 // SSLClientSocketNSS::Core. | 470 // SSLClientSocketNSS::Core. |
397 void AddLogEvent(BoundNetLog* net_log, NetLog::EventType event_type) { | 471 void AddLogEvent(BoundNetLog* net_log, NetLog::EventType event_type) { |
(...skipping 3166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3564 EnsureThreadIdAssigned(); | 3638 EnsureThreadIdAssigned(); |
3565 base::AutoLock auto_lock(lock_); | 3639 base::AutoLock auto_lock(lock_); |
3566 return valid_thread_id_ == base::PlatformThread::CurrentId(); | 3640 return valid_thread_id_ == base::PlatformThread::CurrentId(); |
3567 } | 3641 } |
3568 | 3642 |
3569 ServerBoundCertService* SSLClientSocketNSS::GetServerBoundCertService() const { | 3643 ServerBoundCertService* SSLClientSocketNSS::GetServerBoundCertService() const { |
3570 return server_bound_cert_service_; | 3644 return server_bound_cert_service_; |
3571 } | 3645 } |
3572 | 3646 |
3573 } // namespace net | 3647 } // namespace net |
OLD | NEW |