| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 is automatically generated by transport_security_state_static_gener
ate.go | 5 #ifndef NET_BASE_PUBLIC_KEY_HASHES_ |
| 6 | 6 #define NET_BASE_PUBLIC_KEY_HASHES_ |
| 7 #ifndef NET_BASE_TRANSPORT_SECURITY_STATE_STATIC_H_ | |
| 8 #define NET_BASE_TRANSPORT_SECURITY_STATE_STATIC_H_ | |
| 9 #pragma once | 7 #pragma once |
| 10 | 8 |
| 11 // These are SubjectPublicKeyInfo hashes for public key pinning. The | 9 // This file contains SubjectPublicKeyInfo hashes for public key pinning. The |
| 12 // hashes are base64 encoded, SHA1 digests. | 10 // hashes are base64 encoded, SHA1 digests. |
| 13 | 11 |
| 14 static const char kSPKIHash_TestSPKI[] = | |
| 15 "sha1/AAAAAAAAAAAAAAAAAAAAAAAAAAA="; | |
| 16 | |
| 17 #if 0 | 12 #if 0 |
| 18 -----BEGIN CERTIFICATE----- | 13 -----BEGIN CERTIFICATE----- |
| 19 MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG | 14 MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG |
| 20 A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz | 15 A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz |
| 21 cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 | 16 cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 |
| 22 MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV | 17 MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV |
| 23 BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt | 18 BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt |
| 24 YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN | 19 YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN |
| 25 ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE | 20 ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE |
| 26 BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is | 21 BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 Af8CAQAwOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20v | 72 Af8CAQAwOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20v |
| 78 Y3Jscy9zZWN1cmVjYS5jcmwwDQYJKoZIhvcNAQEFBQADgYEAuIojxkiWsRF8YHde | 73 Y3Jscy9zZWN1cmVjYS5jcmwwDQYJKoZIhvcNAQEFBQADgYEAuIojxkiWsRF8YHde |
| 79 BZqrocb6ghwYB8TrgbCoZutJqOkM0ymt9e8kTP3kS8p/XmOrmSfLnzYhLLkQYGfN | 74 BZqrocb6ghwYB8TrgbCoZutJqOkM0ymt9e8kTP3kS8p/XmOrmSfLnzYhLLkQYGfN |
| 80 0rTw8Ktx5YtaiScRhKqOv5nwnQkhClIZmloJ0pC3+gz4fniisIWvXEyZ2VxVKfml | 75 0rTw8Ktx5YtaiScRhKqOv5nwnQkhClIZmloJ0pC3+gz4fniisIWvXEyZ2VxVKfml |
| 81 UUIuOss4jHg7y/j7lYe8vJD5UDI= | 76 UUIuOss4jHg7y/j7lYe8vJD5UDI= |
| 82 -----END CERTIFICATE----- | 77 -----END CERTIFICATE----- |
| 83 #endif | 78 #endif |
| 84 static const char kSPKIHash_Google1024[] = | 79 static const char kSPKIHash_Google1024[] = |
| 85 "sha1/QMVAHW+MuvCLAO3vse6H0AWzuc0="; | 80 "sha1/QMVAHW+MuvCLAO3vse6H0AWzuc0="; |
| 86 | 81 |
| 82 // Not yet used publicly. |
| 87 static const char kSPKIHash_Google2048[] = | 83 static const char kSPKIHash_Google2048[] = |
| 88 "sha1/AbkhxY0L343gKf+cki7NVWp+ozk="; | 84 "sha1/AbkhxY0L343gKf+cki7NVWp+ozk="; |
| 89 | 85 |
| 90 #if 0 | 86 #if 0 |
| 91 -----BEGIN CERTIFICATE----- | 87 -----BEGIN CERTIFICATE----- |
| 92 MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV | 88 MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV |
| 93 UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy | 89 UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy |
| 94 dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 | 90 dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 |
| 95 MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx | 91 MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx |
| 96 dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B | 92 dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 320 eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF | 316 eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF |
| 321 hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 | 317 hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 |
| 322 Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe | 318 Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe |
| 323 vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep | 319 vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep |
| 324 +OkuE6N36B9K | 320 +OkuE6N36B9K |
| 325 -----END CERTIFICATE----- | 321 -----END CERTIFICATE----- |
| 326 #endif | 322 #endif |
| 327 static const char kSPKIHash_DigiCertEVRoot[] = | 323 static const char kSPKIHash_DigiCertEVRoot[] = |
| 328 "sha1/gzF+YoVCU9bXeDGQ7JGQVumRueM="; | 324 "sha1/gzF+YoVCU9bXeDGQ7JGQVumRueM="; |
| 329 | 325 |
| 326 // Not public |
| 330 static const char kSPKIHash_Tor1[] = | 327 static const char kSPKIHash_Tor1[] = |
| 331 "sha1/juNxSTv9UANmpC9kF5GKpmWNx3Y="; | 328 "sha1/juNxSTv9UANmpC9kF5GKpmWNx3Y="; |
| 332 | |
| 333 static const char kSPKIHash_Tor2[] = | 329 static const char kSPKIHash_Tor2[] = |
| 334 "sha1/lia43lPolzSPVIq34Dw57uYcLD8="; | 330 "sha1/lia43lPolzSPVIq34Dw57uYcLD8="; |
| 335 | |
| 336 static const char kSPKIHash_Tor3[] = | 331 static const char kSPKIHash_Tor3[] = |
| 337 "sha1/rzEyQIKOh77j87n5bjWUNguXF8Y="; | 332 "sha1/rzEyQIKOh77j87n5bjWUNguXF8Y="; |
| 338 | 333 |
| 339 #if 0 | 334 #if 0 |
| 340 -----BEGIN CERTIFICATE----- | 335 -----BEGIN CERTIFICATE----- |
| 341 MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ | 336 MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ |
| 342 BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh | 337 BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh |
| 343 c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05 | 338 c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05 |
| 344 NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD | 339 NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD |
| 345 VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp | 340 VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 576 seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz | 571 seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz |
| 577 4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ | 572 4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ |
| 578 BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR | 573 BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR |
| 579 lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 | 574 lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 |
| 580 7M2CYfE45k+XmCpajQ== | 575 7M2CYfE45k+XmCpajQ== |
| 581 -----END CERTIFICATE----- | 576 -----END CERTIFICATE----- |
| 582 #endif | 577 #endif |
| 583 static const char kSPKIHash_VeriSignUniversal[] = | 578 static const char kSPKIHash_VeriSignUniversal[] = |
| 584 "sha1/u8I+KQuzKHcdrT6iTb30I70GsD0="; | 579 "sha1/u8I+KQuzKHcdrT6iTb30I70GsD0="; |
| 585 | 580 |
| 581 // Not public |
| 586 static const char kSPKIHash_Twitter1[] = | 582 static const char kSPKIHash_Twitter1[] = |
| 587 "sha1/Vv7zwhR9TtOIN/29MFI4cgHld40="; | 583 "sha1/Vv7zwhR9TtOIN/29MFI4cgHld40="; |
| 588 | 584 |
| 589 #if 0 | 585 #if 0 |
| 590 -----BEGIN CERTIFICATE----- | 586 -----BEGIN CERTIFICATE----- |
| 591 MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW | 587 MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW |
| 592 MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs | 588 MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs |
| 593 IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG | 589 IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG |
| 594 EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg | 590 EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg |
| 595 R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A | 591 R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 730 AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH | 726 AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH |
| 731 SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G | 727 SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G |
| 732 spki4cErx5z481+oghLrGREt | 728 spki4cErx5z481+oghLrGREt |
| 733 -----END CERTIFICATE----- | 729 -----END CERTIFICATE----- |
| 734 #endif | 730 #endif |
| 735 static const char kSPKIHash_GeoTrustPrimary_G3[] = | 731 static const char kSPKIHash_GeoTrustPrimary_G3[] = |
| 736 "sha1/nKmNAK90Dd2BgNITRaWLjy6UONY="; | 732 "sha1/nKmNAK90Dd2BgNITRaWLjy6UONY="; |
| 737 | 733 |
| 738 #if 0 | 734 #if 0 |
| 739 -----BEGIN CERTIFICATE----- | 735 -----BEGIN CERTIFICATE----- |
| 740 MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML | 736 MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u |
| 741 RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp | 737 ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp |
| 742 bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 | 738 bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV |
| 743 IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp | 739 BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx |
| 744 ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 | 740 NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 |
| 745 MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 | 741 d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl |
| 746 LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp | 742 MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u |
| 747 YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG | 743 ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A |
| 748 A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp | 744 MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL |
| 749 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq | 745 Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr |
| 750 K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe | 746 hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW |
| 751 sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX | 747 nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi |
| 752 MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT | 748 VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E |
| 753 XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ | 749 BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ |
| 754 HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH | 750 KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy |
| 755 4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV | 751 T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf |
| 756 HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub | 752 zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT |
| 757 j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo | 753 J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e |
| 758 U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf | 754 nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE= |
| 759 zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b | |
| 760 u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ | |
| 761 bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er | |
| 762 fF6adulZkMV8gzURZVE= | |
| 763 -----END CERTIFICATE----- | 755 -----END CERTIFICATE----- |
| 764 #endif | 756 #endif |
| 765 static const char kSPKIHash_Entrust_2048[] = | 757 static const char kSPKIHash_Entrust_2048[] = |
| 766 "sha1/VeSB0RGAvtiJuQijMfmhJAkWuXA="; | 758 "sha1/VeSB0RGAvtiJuQijMfmhJAkWuXA="; |
| 767 | 759 |
| 768 #if 0 | 760 #if 0 |
| 769 -----BEGIN CERTIFICATE----- | 761 -----BEGIN CERTIFICATE----- |
| 770 MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC | 762 MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC |
| 771 VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 | 763 VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 |
| 772 Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW | 764 Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW |
| (...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1236 r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4 | 1228 r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4 |
| 1237 04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r | 1229 04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r |
| 1238 GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9 | 1230 GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9 |
| 1239 3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P | 1231 3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P |
| 1240 lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ | 1232 lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ |
| 1241 -----END CERTIFICATE----- | 1233 -----END CERTIFICATE----- |
| 1242 #endif | 1234 #endif |
| 1243 static const char kSPKIHash_GTECyberTrustGlobalRoot[] = | 1235 static const char kSPKIHash_GTECyberTrustGlobalRoot[] = |
| 1244 "sha1/WXkS3mF11m/EI7d3E3THlt5viHI="; | 1236 "sha1/WXkS3mF11m/EI7d3E3THlt5viHI="; |
| 1245 | 1237 |
| 1246 // The following is static data describing the hosts that are hardcoded with | 1238 #endif // NET_BASE_PUBLIC_KEY_HASHES_ |
| 1247 // certificate pins or HSTS information. | 1239 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 1240 // Use of this source code is governed by a BSD-style license that can be |
| 1241 // found in the LICENSE file. |
| 1242 |
| 1243 #include "net/base/transport_security_state.h" |
| 1244 |
| 1245 #if defined(USE_OPENSSL) |
| 1246 #include <openssl/ecdsa.h> |
| 1247 #include <openssl/ssl.h> |
| 1248 #else // !defined(USE_OPENSSL) |
| 1249 #include <cryptohi.h> |
| 1250 #include <hasht.h> |
| 1251 #include <keyhi.h> |
| 1252 #include <pk11pub.h> |
| 1253 #include <nspr.h> |
| 1254 #endif |
| 1255 |
| 1256 #include <algorithm> |
| 1257 #include <utility> |
| 1258 |
| 1259 #include "base/base64.h" |
| 1260 #include "base/json/json_reader.h" |
| 1261 #include "base/json/json_writer.h" |
| 1262 #include "base/logging.h" |
| 1263 #include "base/memory/scoped_ptr.h" |
| 1264 #include "base/metrics/histogram.h" |
| 1265 #include "base/sha1.h" |
| 1266 #include "base/string_number_conversions.h" |
| 1267 #include "base/string_tokenizer.h" |
| 1268 #include "base/string_util.h" |
| 1269 #include "base/time.h" |
| 1270 #include "base/utf_string_conversions.h" |
| 1271 #include "base/values.h" |
| 1272 #include "crypto/sha2.h" |
| 1273 #include "googleurl/src/gurl.h" |
| 1274 #include "net/base/asn1_util.h" |
| 1275 #include "net/base/dns_util.h" |
| 1276 #include "net/base/public_key_hashes.h" |
| 1277 #include "net/base/ssl_info.h" |
| 1278 #include "net/base/x509_certificate.h" |
| 1279 #include "net/http/http_util.h" |
| 1280 |
| 1281 #if defined(USE_OPENSSL) |
| 1282 #include "crypto/openssl_util.h" |
| 1283 #endif |
| 1284 |
| 1285 namespace net { |
| 1286 |
| 1287 const long int TransportSecurityState::kMaxHSTSAgeSecs = 86400 * 365; // 1 year |
| 1288 |
| 1289 TransportSecurityState::TransportSecurityState(const std::string& hsts_hosts) |
| 1290 : delegate_(NULL) { |
| 1291 if (!hsts_hosts.empty()) { |
| 1292 bool dirty; |
| 1293 Deserialise(hsts_hosts, &dirty, &forced_hosts_); |
| 1294 } |
| 1295 } |
| 1296 |
| 1297 static std::string HashHost(const std::string& canonicalized_host) { |
| 1298 char hashed[crypto::kSHA256Length]; |
| 1299 crypto::SHA256HashString(canonicalized_host, hashed, sizeof(hashed)); |
| 1300 return std::string(hashed, sizeof(hashed)); |
| 1301 } |
| 1302 |
| 1303 void TransportSecurityState::SetDelegate( |
| 1304 TransportSecurityState::Delegate* delegate) { |
| 1305 delegate_ = delegate; |
| 1306 } |
| 1307 |
| 1308 void TransportSecurityState::EnableHost(const std::string& host, |
| 1309 const DomainState& state) { |
| 1310 DCHECK(CalledOnValidThread()); |
| 1311 |
| 1312 const std::string canonicalized_host = CanonicalizeHost(host); |
| 1313 if (canonicalized_host.empty()) |
| 1314 return; |
| 1315 |
| 1316 // Only override a preloaded state if the new state describes a more strict |
| 1317 // policy. TODO(palmer): Reconsider this? |
| 1318 DomainState existing_state; |
| 1319 if (IsPreloadedSTS(canonicalized_host, true, &existing_state) && |
| 1320 canonicalized_host == CanonicalizeHost(existing_state.domain) && |
| 1321 existing_state.IsMoreStrict(state)) { |
| 1322 return; |
| 1323 } |
| 1324 |
| 1325 // Use the original creation date if we already have this host. |
| 1326 DomainState state_copy(state); |
| 1327 if (GetDomainState(&existing_state, host, true) && |
| 1328 !existing_state.created.is_null()) { |
| 1329 state_copy.created = existing_state.created; |
| 1330 } |
| 1331 |
| 1332 // We don't store these values. |
| 1333 state_copy.preloaded = false; |
| 1334 state_copy.domain.clear(); |
| 1335 |
| 1336 enabled_hosts_[HashHost(canonicalized_host)] = state_copy; |
| 1337 DirtyNotify(); |
| 1338 } |
| 1339 |
| 1340 bool TransportSecurityState::DeleteHost(const std::string& host) { |
| 1341 DCHECK(CalledOnValidThread()); |
| 1342 |
| 1343 const std::string canonicalized_host = CanonicalizeHost(host); |
| 1344 if (canonicalized_host.empty()) |
| 1345 return false; |
| 1346 |
| 1347 std::map<std::string, DomainState>::iterator i = enabled_hosts_.find( |
| 1348 HashHost(canonicalized_host)); |
| 1349 if (i != enabled_hosts_.end()) { |
| 1350 enabled_hosts_.erase(i); |
| 1351 DirtyNotify(); |
| 1352 return true; |
| 1353 } |
| 1354 return false; |
| 1355 } |
| 1356 |
| 1357 bool TransportSecurityState::HasPinsForHost(DomainState* result, |
| 1358 const std::string& host, |
| 1359 bool sni_available) { |
| 1360 DCHECK(CalledOnValidThread()); |
| 1361 |
| 1362 return HasMetadata(result, host, sni_available) && |
| 1363 (!result->dynamic_spki_hashes.empty() || |
| 1364 !result->preloaded_spki_hashes.empty()); |
| 1365 } |
| 1366 |
| 1367 bool TransportSecurityState::GetDomainState(DomainState* result, |
| 1368 const std::string& host, |
| 1369 bool sni_available) { |
| 1370 DCHECK(CalledOnValidThread()); |
| 1371 |
| 1372 return HasMetadata(result, host, sni_available); |
| 1373 } |
| 1374 |
| 1375 bool TransportSecurityState::HasMetadata(DomainState* result, |
| 1376 const std::string& host, |
| 1377 bool sni_available) { |
| 1378 DCHECK(CalledOnValidThread()); |
| 1379 |
| 1380 DomainState state; |
| 1381 const std::string canonicalized_host = CanonicalizeHost(host); |
| 1382 if (canonicalized_host.empty()) |
| 1383 return false; |
| 1384 |
| 1385 bool has_preload = IsPreloadedSTS(canonicalized_host, sni_available, &state); |
| 1386 std::string canonicalized_preload = CanonicalizeHost(state.domain); |
| 1387 |
| 1388 base::Time current_time(base::Time::Now()); |
| 1389 |
| 1390 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { |
| 1391 std::string host_sub_chunk(&canonicalized_host[i], |
| 1392 canonicalized_host.size() - i); |
| 1393 // Exact match of a preload always wins. |
| 1394 if (has_preload && host_sub_chunk == canonicalized_preload) { |
| 1395 *result = state; |
| 1396 return true; |
| 1397 } |
| 1398 |
| 1399 std::map<std::string, DomainState>::iterator j = |
| 1400 enabled_hosts_.find(HashHost(host_sub_chunk)); |
| 1401 if (j == enabled_hosts_.end()) |
| 1402 continue; |
| 1403 |
| 1404 if (current_time > j->second.expiry && |
| 1405 current_time > j->second.dynamic_spki_hashes_expiry) { |
| 1406 enabled_hosts_.erase(j); |
| 1407 DirtyNotify(); |
| 1408 continue; |
| 1409 } |
| 1410 |
| 1411 state = j->second; |
| 1412 state.domain = DNSDomainToString(host_sub_chunk); |
| 1413 |
| 1414 // Succeed if we matched the domain exactly or if subdomain matches are |
| 1415 // allowed. |
| 1416 if (i == 0 || j->second.include_subdomains) { |
| 1417 *result = state; |
| 1418 return true; |
| 1419 } |
| 1420 |
| 1421 return false; |
| 1422 } |
| 1423 |
| 1424 return false; |
| 1425 } |
| 1426 |
| 1427 void TransportSecurityState::DeleteSince(const base::Time& time) { |
| 1428 DCHECK(CalledOnValidThread()); |
| 1429 |
| 1430 bool dirtied = false; |
| 1431 |
| 1432 std::map<std::string, DomainState>::iterator i = enabled_hosts_.begin(); |
| 1433 while (i != enabled_hosts_.end()) { |
| 1434 if (i->second.created >= time) { |
| 1435 dirtied = true; |
| 1436 enabled_hosts_.erase(i++); |
| 1437 } else { |
| 1438 i++; |
| 1439 } |
| 1440 } |
| 1441 |
| 1442 if (dirtied) |
| 1443 DirtyNotify(); |
| 1444 } |
| 1445 |
| 1446 // MaxAgeToInt converts a string representation of a number of seconds into a |
| 1447 // int. We use strtol in order to handle overflow correctly. The string may |
| 1448 // contain an arbitary number which we should truncate correctly rather than |
| 1449 // throwing a parse failure. |
| 1450 static bool MaxAgeToInt(std::string::const_iterator begin, |
| 1451 std::string::const_iterator end, |
| 1452 int* result) { |
| 1453 const std::string s(begin, end); |
| 1454 char* endptr; |
| 1455 long int i = strtol(s.data(), &endptr, 10 /* base */); |
| 1456 if (*endptr || i < 0) |
| 1457 return false; |
| 1458 if (i > TransportSecurityState::kMaxHSTSAgeSecs) |
| 1459 i = TransportSecurityState::kMaxHSTSAgeSecs; |
| 1460 *result = i; |
| 1461 return true; |
| 1462 } |
| 1463 |
| 1464 // Strip, Split, StringPair, and ParsePins are private implementation details |
| 1465 // of ParsePinsHeader(std::string&, DomainState&). |
| 1466 static std::string Strip(const std::string& source) { |
| 1467 if (source.empty()) |
| 1468 return source; |
| 1469 |
| 1470 std::string::const_iterator start = source.begin(); |
| 1471 std::string::const_iterator end = source.end(); |
| 1472 HttpUtil::TrimLWS(&start, &end); |
| 1473 return std::string(start, end); |
| 1474 } |
| 1475 |
| 1476 typedef std::pair<std::string, std::string> StringPair; |
| 1477 |
| 1478 static StringPair Split(const std::string& source, char delimiter) { |
| 1479 StringPair pair; |
| 1480 size_t point = source.find(delimiter); |
| 1481 |
| 1482 pair.first = source.substr(0, point); |
| 1483 if (std::string::npos != point) |
| 1484 pair.second = source.substr(point + 1); |
| 1485 |
| 1486 return pair; |
| 1487 } |
| 1488 |
| 1489 // TODO(palmer): Support both sha256 and sha1. This will require additional |
| 1490 // infrastructure code changes and can come in a later patch. |
| 1491 // |
| 1492 // static |
| 1493 bool TransportSecurityState::ParsePin(const std::string& value, |
| 1494 SHA1Fingerprint* out) { |
| 1495 StringPair slash = Split(Strip(value), '/'); |
| 1496 if (slash.first != "sha1") |
| 1497 return false; |
| 1498 |
| 1499 std::string decoded; |
| 1500 if (!base::Base64Decode(slash.second, &decoded) || |
| 1501 decoded.size() != arraysize(out->data)) { |
| 1502 return false; |
| 1503 } |
| 1504 |
| 1505 memcpy(out->data, decoded.data(), arraysize(out->data)); |
| 1506 return true; |
| 1507 } |
| 1508 |
| 1509 static bool ParseAndAppendPin(const std::string& value, |
| 1510 FingerprintVector* fingerprints) { |
| 1511 // The base64'd fingerprint MUST be a quoted-string. 20 bytes base64'd is 28 |
| 1512 // characters; 32 bytes base64'd is 44 characters. TODO(palmer): Support |
| 1513 // SHA256. |
| 1514 size_t size = value.size(); |
| 1515 if (size != 30 || value[0] != '"' || value[size - 1] != '"') |
| 1516 return false; |
| 1517 |
| 1518 std::string unquoted = HttpUtil::Unquote(value); |
| 1519 std::string decoded; |
| 1520 SHA1Fingerprint fp; |
| 1521 |
| 1522 if (!base::Base64Decode(unquoted, &decoded) || |
| 1523 decoded.size() != arraysize(fp.data)) { |
| 1524 return false; |
| 1525 } |
| 1526 |
| 1527 memcpy(fp.data, decoded.data(), arraysize(fp.data)); |
| 1528 fingerprints->push_back(fp); |
| 1529 return true; |
| 1530 } |
| 1531 |
| 1532 // static |
| 1533 bool TransportSecurityState::GetPublicKeyHash( |
| 1534 const X509Certificate& cert, SHA1Fingerprint* spki_hash) { |
| 1535 std::string der_bytes; |
| 1536 if (!X509Certificate::GetDEREncoded(cert.os_cert_handle(), &der_bytes)) |
| 1537 return false; |
| 1538 |
| 1539 base::StringPiece spki; |
| 1540 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki)) |
| 1541 return false; |
| 1542 |
| 1543 base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(spki.data()), |
| 1544 spki.size(), spki_hash->data); |
| 1545 |
| 1546 return true; |
| 1547 } |
| 1548 |
| 1549 struct FingerprintsEqualPredicate { |
| 1550 explicit FingerprintsEqualPredicate(const SHA1Fingerprint& fingerprint) : |
| 1551 fingerprint_(fingerprint) {} |
| 1552 |
| 1553 bool operator()(const SHA1Fingerprint& other) const { |
| 1554 return fingerprint_.Equals(other); |
| 1555 } |
| 1556 |
| 1557 const SHA1Fingerprint& fingerprint_; |
| 1558 }; |
| 1559 |
| 1560 // Returns true iff there is an item in |pins| which is not present in |
| 1561 // |from_cert_chain|. Such an SPKI hash is called a "backup pin". |
| 1562 static bool IsBackupPinPresent(const FingerprintVector& pins, |
| 1563 const FingerprintVector& from_cert_chain) { |
| 1564 for (FingerprintVector::const_iterator |
| 1565 i = pins.begin(); i != pins.end(); ++i) { |
| 1566 FingerprintVector::const_iterator j = |
| 1567 std::find_if(from_cert_chain.begin(), from_cert_chain.end(), |
| 1568 FingerprintsEqualPredicate(*i)); |
| 1569 if (j == from_cert_chain.end()) |
| 1570 return true; |
| 1571 } |
| 1572 |
| 1573 return false; |
| 1574 } |
| 1575 |
| 1576 static bool HashesIntersect(const FingerprintVector& a, |
| 1577 const FingerprintVector& b) { |
| 1578 for (FingerprintVector::const_iterator |
| 1579 i = a.begin(); i != a.end(); ++i) { |
| 1580 FingerprintVector::const_iterator j = |
| 1581 std::find_if(b.begin(), b.end(), FingerprintsEqualPredicate(*i)); |
| 1582 if (j != b.end()) |
| 1583 return true; |
| 1584 } |
| 1585 |
| 1586 return false; |
| 1587 } |
| 1588 |
| 1589 // Returns true iff |pins| contains both a live and a backup pin. A live pin |
| 1590 // is a pin whose SPKI is present in the certificate chain in |ssl_info|. A |
| 1591 // backup pin is a pin intended for disaster recovery, not day-to-day use, and |
| 1592 // thus must be absent from the certificate chain. The Public-Key-Pins header |
| 1593 // specification requires both. |
| 1594 static bool IsPinListValid(const FingerprintVector& pins, |
| 1595 const SSLInfo& ssl_info) { |
| 1596 if (pins.size() < 2) |
| 1597 return false; |
| 1598 |
| 1599 const FingerprintVector& from_cert_chain = ssl_info.public_key_hashes; |
| 1600 if (from_cert_chain.empty()) |
| 1601 return false; |
| 1602 |
| 1603 return IsBackupPinPresent(pins, from_cert_chain) && |
| 1604 HashesIntersect(pins, from_cert_chain); |
| 1605 } |
| 1606 |
| 1607 // "Public-Key-Pins" ":" |
| 1608 // "max-age" "=" delta-seconds ";" |
| 1609 // "pin-" algo "=" base64 [ ";" ... ] |
| 1610 // |
| 1611 // static |
| 1612 bool TransportSecurityState::ParsePinsHeader(const std::string& value, |
| 1613 const SSLInfo& ssl_info, |
| 1614 DomainState* state) { |
| 1615 bool parsed_max_age = false; |
| 1616 int max_age = 0; |
| 1617 FingerprintVector pins; |
| 1618 |
| 1619 std::string source = value; |
| 1620 |
| 1621 while (!source.empty()) { |
| 1622 StringPair semicolon = Split(source, ';'); |
| 1623 semicolon.first = Strip(semicolon.first); |
| 1624 semicolon.second = Strip(semicolon.second); |
| 1625 StringPair equals = Split(semicolon.first, '='); |
| 1626 equals.first = Strip(equals.first); |
| 1627 equals.second = Strip(equals.second); |
| 1628 |
| 1629 if (LowerCaseEqualsASCII(equals.first, "max-age")) { |
| 1630 if (equals.second.empty() || |
| 1631 !MaxAgeToInt(equals.second.begin(), equals.second.end(), &max_age)) { |
| 1632 return false; |
| 1633 } |
| 1634 if (max_age > kMaxHSTSAgeSecs) |
| 1635 max_age = kMaxHSTSAgeSecs; |
| 1636 parsed_max_age = true; |
| 1637 } else if (LowerCaseEqualsASCII(equals.first, "pin-sha1")) { |
| 1638 if (!ParseAndAppendPin(equals.second, &pins)) |
| 1639 return false; |
| 1640 } else if (LowerCaseEqualsASCII(equals.first, "pin-sha256")) { |
| 1641 // TODO(palmer) |
| 1642 } else { |
| 1643 // Silently ignore unknown directives for forward compatibility. |
| 1644 } |
| 1645 |
| 1646 source = semicolon.second; |
| 1647 } |
| 1648 |
| 1649 if (!parsed_max_age || !IsPinListValid(pins, ssl_info)) |
| 1650 return false; |
| 1651 |
| 1652 state->max_age = max_age; |
| 1653 state->dynamic_spki_hashes_expiry = |
| 1654 base::Time::Now() + base::TimeDelta::FromSeconds(max_age); |
| 1655 |
| 1656 state->dynamic_spki_hashes.clear(); |
| 1657 if (max_age > 0) { |
| 1658 for (FingerprintVector::const_iterator i = pins.begin(); |
| 1659 i != pins.end(); i++) { |
| 1660 state->dynamic_spki_hashes.push_back(*i); |
| 1661 } |
| 1662 } |
| 1663 |
| 1664 return true; |
| 1665 } |
| 1666 |
| 1667 // "Strict-Transport-Security" ":" |
| 1668 // "max-age" "=" delta-seconds [ ";" "includeSubDomains" ] |
| 1669 // |
| 1670 // static |
| 1671 bool TransportSecurityState::ParseHeader(const std::string& value, |
| 1672 int* max_age, |
| 1673 bool* include_subdomains) { |
| 1674 DCHECK(max_age); |
| 1675 DCHECK(include_subdomains); |
| 1676 |
| 1677 int max_age_candidate = 0; |
| 1678 |
| 1679 enum ParserState { |
| 1680 START, |
| 1681 AFTER_MAX_AGE_LABEL, |
| 1682 AFTER_MAX_AGE_EQUALS, |
| 1683 AFTER_MAX_AGE, |
| 1684 AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER, |
| 1685 AFTER_INCLUDE_SUBDOMAINS, |
| 1686 } state = START; |
| 1687 |
| 1688 StringTokenizer tokenizer(value, " \t=;"); |
| 1689 tokenizer.set_options(StringTokenizer::RETURN_DELIMS); |
| 1690 while (tokenizer.GetNext()) { |
| 1691 DCHECK(!tokenizer.token_is_delim() || tokenizer.token().length() == 1); |
| 1692 switch (state) { |
| 1693 case START: |
| 1694 if (IsAsciiWhitespace(*tokenizer.token_begin())) |
| 1695 continue; |
| 1696 if (!LowerCaseEqualsASCII(tokenizer.token(), "max-age")) |
| 1697 return false; |
| 1698 state = AFTER_MAX_AGE_LABEL; |
| 1699 break; |
| 1700 |
| 1701 case AFTER_MAX_AGE_LABEL: |
| 1702 if (IsAsciiWhitespace(*tokenizer.token_begin())) |
| 1703 continue; |
| 1704 if (*tokenizer.token_begin() != '=') |
| 1705 return false; |
| 1706 DCHECK_EQ(tokenizer.token().length(), 1U); |
| 1707 state = AFTER_MAX_AGE_EQUALS; |
| 1708 break; |
| 1709 |
| 1710 case AFTER_MAX_AGE_EQUALS: |
| 1711 if (IsAsciiWhitespace(*tokenizer.token_begin())) |
| 1712 continue; |
| 1713 if (!MaxAgeToInt(tokenizer.token_begin(), |
| 1714 tokenizer.token_end(), |
| 1715 &max_age_candidate)) |
| 1716 return false; |
| 1717 state = AFTER_MAX_AGE; |
| 1718 break; |
| 1719 |
| 1720 case AFTER_MAX_AGE: |
| 1721 if (IsAsciiWhitespace(*tokenizer.token_begin())) |
| 1722 continue; |
| 1723 if (*tokenizer.token_begin() != ';') |
| 1724 return false; |
| 1725 state = AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER; |
| 1726 break; |
| 1727 |
| 1728 case AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER: |
| 1729 if (IsAsciiWhitespace(*tokenizer.token_begin())) |
| 1730 continue; |
| 1731 if (!LowerCaseEqualsASCII(tokenizer.token(), "includesubdomains")) |
| 1732 return false; |
| 1733 state = AFTER_INCLUDE_SUBDOMAINS; |
| 1734 break; |
| 1735 |
| 1736 case AFTER_INCLUDE_SUBDOMAINS: |
| 1737 if (!IsAsciiWhitespace(*tokenizer.token_begin())) |
| 1738 return false; |
| 1739 break; |
| 1740 |
| 1741 default: |
| 1742 NOTREACHED(); |
| 1743 } |
| 1744 } |
| 1745 |
| 1746 // We've consumed all the input. Let's see what state we ended up in. |
| 1747 switch (state) { |
| 1748 case START: |
| 1749 case AFTER_MAX_AGE_LABEL: |
| 1750 case AFTER_MAX_AGE_EQUALS: |
| 1751 return false; |
| 1752 case AFTER_MAX_AGE: |
| 1753 *max_age = max_age_candidate; |
| 1754 *include_subdomains = false; |
| 1755 return true; |
| 1756 case AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER: |
| 1757 return false; |
| 1758 case AFTER_INCLUDE_SUBDOMAINS: |
| 1759 *max_age = max_age_candidate; |
| 1760 *include_subdomains = true; |
| 1761 return true; |
| 1762 default: |
| 1763 NOTREACHED(); |
| 1764 return false; |
| 1765 } |
| 1766 } |
| 1767 |
| 1768 // Side pinning and superfluous certificates: |
| 1769 // |
| 1770 // In SSLClientSocketNSS::DoVerifyCertComplete we look for certificates with a |
| 1771 // Subject of CN=meta. When we find one we'll currently try and parse side |
| 1772 // pinned key from it. |
| 1773 // |
| 1774 // A side pin is a key which can be pinned to, but also can be kept offline and |
| 1775 // still held by the site owner. The CN=meta certificate is just a backwards |
| 1776 // compatiable method of carrying a lump of bytes to the client. (We could use |
| 1777 // a TLS extension just as well, but it's a lot easier for admins to add extra |
| 1778 // certificates to the chain.) |
| 1779 |
| 1780 // A TagMap represents the simple key-value structure that we use. Keys are |
| 1781 // 32-bit ints. Values are byte strings. |
| 1782 typedef std::map<uint32, base::StringPiece> TagMap; |
| 1783 |
| 1784 // ParseTags parses a list of key-value pairs from |in| to |out| and advances |
| 1785 // |in| past the data. The key-value pair data is: |
| 1786 // u16le num_tags |
| 1787 // u32le tag[num_tags] |
| 1788 // u16le lengths[num_tags] |
| 1789 // ...data... |
| 1790 static bool ParseTags(base::StringPiece* in, TagMap *out) { |
| 1791 // Many part of Chrome already assume little-endian. This is just to help |
| 1792 // anyone who should try to port it in the future. |
| 1793 #if defined(__BYTE_ORDER) |
| 1794 // Linux check |
| 1795 COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN, assumes_little_endian); |
| 1796 #elif defined(__BIG_ENDIAN__) |
| 1797 // Mac check |
| 1798 #error assumes little endian |
| 1799 #endif |
| 1800 |
| 1801 uint16 num_tags_16; |
| 1802 if (in->size() < sizeof(num_tags_16)) |
| 1803 return false; |
| 1804 |
| 1805 memcpy(&num_tags_16, in->data(), sizeof(num_tags_16)); |
| 1806 in->remove_prefix(sizeof(num_tags_16)); |
| 1807 unsigned num_tags = num_tags_16; |
| 1808 |
| 1809 if (in->size() < 6 * num_tags) |
| 1810 return false; |
| 1811 |
| 1812 const uint32* tags = reinterpret_cast<const uint32*>(in->data()); |
| 1813 const uint16* lens = reinterpret_cast<const uint16*>( |
| 1814 in->data() + 4*num_tags); |
| 1815 in->remove_prefix(6*num_tags); |
| 1816 |
| 1817 uint32 prev_tag = 0; |
| 1818 for (unsigned i = 0; i < num_tags; i++) { |
| 1819 size_t len = lens[i]; |
| 1820 uint32 tag = tags[i]; |
| 1821 |
| 1822 if (in->size() < len) |
| 1823 return false; |
| 1824 // tags must be in ascending order. |
| 1825 if (i > 0 && prev_tag >= tag) |
| 1826 return false; |
| 1827 (*out)[tag] = base::StringPiece(in->data(), len); |
| 1828 in->remove_prefix(len); |
| 1829 prev_tag = tag; |
| 1830 } |
| 1831 |
| 1832 return true; |
| 1833 } |
| 1834 |
| 1835 // GetTag extracts the data associated with |tag| in |tags|. |
| 1836 static bool GetTag(uint32 tag, const TagMap& tags, base::StringPiece* out) { |
| 1837 TagMap::const_iterator i = tags.find(tag); |
| 1838 if (i == tags.end()) |
| 1839 return false; |
| 1840 |
| 1841 *out = i->second; |
| 1842 return true; |
| 1843 } |
| 1844 |
| 1845 // kP256SubjectPublicKeyInfoPrefix can be prepended onto a P256 elliptic curve |
| 1846 // point in X9.62 format in order to make a valid SubjectPublicKeyInfo. The |
| 1847 // ASN.1 interpretation of these bytes is: |
| 1848 // |
| 1849 // 0:d=0 hl=2 l= 89 cons: SEQUENCE |
| 1850 // 2:d=1 hl=2 l= 19 cons: SEQUENCE |
| 1851 // 4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey |
| 1852 // 13:d=2 hl=2 l= 8 prim: OBJECT :prime256v1 |
| 1853 // 23:d=1 hl=2 l= 66 prim: BIT STRING |
| 1854 static const uint8 kP256SubjectPublicKeyInfoPrefix[] = { |
| 1855 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, |
| 1856 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, |
| 1857 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, |
| 1858 0x42, 0x00, |
| 1859 }; |
| 1860 |
| 1861 // VerifySignature returns true iff |sig| is a valid signature of |
| 1862 // |hash| by |pubkey|. The actual implementation is crypto library |
| 1863 // specific. |
| 1864 static bool VerifySignature(const base::StringPiece& pubkey, |
| 1865 const base::StringPiece& sig, |
| 1866 const base::StringPiece& hash); |
| 1867 |
| 1868 #if defined(USE_OPENSSL) |
| 1869 |
| 1870 static EVP_PKEY* DecodeX962P256PublicKey( |
| 1871 const base::StringPiece& pubkey_bytes) { |
| 1872 // The public key is an X9.62 encoded P256 point. |
| 1873 if (pubkey_bytes.size() != 1 + 2*32) |
| 1874 return NULL; |
| 1875 |
| 1876 std::string pubkey_spki( |
| 1877 reinterpret_cast<const char*>(kP256SubjectPublicKeyInfoPrefix), |
| 1878 sizeof(kP256SubjectPublicKeyInfoPrefix)); |
| 1879 pubkey_spki += pubkey_bytes.as_string(); |
| 1880 |
| 1881 EVP_PKEY* ret = NULL; |
| 1882 const unsigned char* der_pubkey = |
| 1883 reinterpret_cast<const unsigned char*>(pubkey_spki.data()); |
| 1884 d2i_PUBKEY(&ret, &der_pubkey, pubkey_spki.size()); |
| 1885 return ret; |
| 1886 } |
| 1887 |
| 1888 static bool VerifySignature(const base::StringPiece& pubkey, |
| 1889 const base::StringPiece& sig, |
| 1890 const base::StringPiece& hash) { |
| 1891 crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> secpubkey( |
| 1892 DecodeX962P256PublicKey(pubkey)); |
| 1893 if (!secpubkey.get()) |
| 1894 return false; |
| 1895 |
| 1896 |
| 1897 crypto::ScopedOpenSSL<EC_KEY, EC_KEY_free> ec_key( |
| 1898 EVP_PKEY_get1_EC_KEY(secpubkey.get())); |
| 1899 if (!ec_key.get()) |
| 1900 return false; |
| 1901 |
| 1902 return ECDSA_verify(0, reinterpret_cast<const unsigned char*>(hash.data()), |
| 1903 hash.size(), |
| 1904 reinterpret_cast<const unsigned char*>(sig.data()), |
| 1905 sig.size(), ec_key.get()) == 1; |
| 1906 } |
| 1907 |
| 1908 #else |
| 1909 |
| 1910 // DecodeX962P256PublicKey parses an uncompressed, X9.62 format, P256 elliptic |
| 1911 // curve point from |pubkey_bytes| and returns it as a SECKEYPublicKey. |
| 1912 static SECKEYPublicKey* DecodeX962P256PublicKey( |
| 1913 const base::StringPiece& pubkey_bytes) { |
| 1914 // The public key is an X9.62 encoded P256 point. |
| 1915 if (pubkey_bytes.size() != 1 + 2*32) |
| 1916 return NULL; |
| 1917 |
| 1918 std::string pubkey_spki( |
| 1919 reinterpret_cast<const char*>(kP256SubjectPublicKeyInfoPrefix), |
| 1920 sizeof(kP256SubjectPublicKeyInfoPrefix)); |
| 1921 pubkey_spki += pubkey_bytes.as_string(); |
| 1922 |
| 1923 SECItem der; |
| 1924 memset(&der, 0, sizeof(der)); |
| 1925 der.data = reinterpret_cast<uint8*>(const_cast<char*>(pubkey_spki.data())); |
| 1926 der.len = pubkey_spki.size(); |
| 1927 |
| 1928 CERTSubjectPublicKeyInfo* spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&der); |
| 1929 if (!spki) |
| 1930 return NULL; |
| 1931 SECKEYPublicKey* public_key = SECKEY_ExtractPublicKey(spki); |
| 1932 SECKEY_DestroySubjectPublicKeyInfo(spki); |
| 1933 |
| 1934 return public_key; |
| 1935 } |
| 1936 |
| 1937 static bool VerifySignature(const base::StringPiece& pubkey, |
| 1938 const base::StringPiece& sig, |
| 1939 const base::StringPiece& hash) { |
| 1940 SECKEYPublicKey* secpubkey = DecodeX962P256PublicKey(pubkey); |
| 1941 if (!secpubkey) |
| 1942 return false; |
| 1943 |
| 1944 SECItem sigitem; |
| 1945 memset(&sigitem, 0, sizeof(sigitem)); |
| 1946 sigitem.data = reinterpret_cast<uint8*>(const_cast<char*>(sig.data())); |
| 1947 sigitem.len = sig.size(); |
| 1948 |
| 1949 // |decoded_sigitem| is newly allocated, as is the data that it points to. |
| 1950 SECItem* decoded_sigitem = DSAU_DecodeDerSigToLen( |
| 1951 &sigitem, SECKEY_SignatureLen(secpubkey)); |
| 1952 |
| 1953 if (!decoded_sigitem) { |
| 1954 SECKEY_DestroyPublicKey(secpubkey); |
| 1955 return false; |
| 1956 } |
| 1957 |
| 1958 SECItem hashitem; |
| 1959 memset(&hashitem, 0, sizeof(hashitem)); |
| 1960 hashitem.data = reinterpret_cast<unsigned char*>( |
| 1961 const_cast<char*>(hash.data())); |
| 1962 hashitem.len = hash.size(); |
| 1963 |
| 1964 SECStatus rv = PK11_Verify(secpubkey, decoded_sigitem, &hashitem, NULL); |
| 1965 SECKEY_DestroyPublicKey(secpubkey); |
| 1966 SECITEM_FreeItem(decoded_sigitem, PR_TRUE); |
| 1967 return rv == SECSuccess; |
| 1968 } |
| 1969 |
| 1970 #endif // !defined(USE_OPENSSL) |
| 1971 |
| 1972 // These are the tag values that we use. Tags are little-endian on the wire and |
| 1973 // these values correspond to the ASCII of the name. |
| 1974 static const uint32 kTagALGO = 0x4f474c41; |
| 1975 static const uint32 kTagP256 = 0x36353250; |
| 1976 static const uint32 kTagPUBK = 0x4b425550; |
| 1977 static const uint32 kTagSIG = 0x474953; |
| 1978 static const uint32 kTagSPIN = 0x4e495053; |
| 1979 |
| 1980 // static |
| 1981 bool TransportSecurityState::ParseSidePin( |
| 1982 const base::StringPiece& leaf_spki, |
| 1983 const base::StringPiece& in_side_info, |
| 1984 FingerprintVector* out_pub_key_hash) { |
| 1985 base::StringPiece side_info(in_side_info); |
| 1986 |
| 1987 TagMap outer; |
| 1988 if (!ParseTags(&side_info, &outer)) |
| 1989 return false; |
| 1990 // trailing data is not allowed |
| 1991 if (side_info.size()) |
| 1992 return false; |
| 1993 |
| 1994 base::StringPiece side_pin_bytes; |
| 1995 if (!GetTag(kTagSPIN, outer, &side_pin_bytes)) |
| 1996 return false; |
| 1997 |
| 1998 bool have_parsed_a_key = false; |
| 1999 uint8 leaf_spki_hash[crypto::kSHA256Length]; |
| 2000 bool have_leaf_spki_hash = false; |
| 2001 |
| 2002 while (side_pin_bytes.size() > 0) { |
| 2003 TagMap side_pin; |
| 2004 if (!ParseTags(&side_pin_bytes, &side_pin)) |
| 2005 return false; |
| 2006 |
| 2007 base::StringPiece algo, pubkey, sig; |
| 2008 if (!GetTag(kTagALGO, side_pin, &algo) || |
| 2009 !GetTag(kTagPUBK, side_pin, &pubkey) || |
| 2010 !GetTag(kTagSIG, side_pin, &sig)) { |
| 2011 return false; |
| 2012 } |
| 2013 |
| 2014 if (algo.size() != sizeof(kTagP256) || |
| 2015 0 != memcmp(algo.data(), &kTagP256, sizeof(kTagP256))) { |
| 2016 // We don't support anything but P256 at the moment. |
| 2017 continue; |
| 2018 } |
| 2019 |
| 2020 if (!have_leaf_spki_hash) { |
| 2021 crypto::SHA256HashString( |
| 2022 leaf_spki.as_string(), leaf_spki_hash, sizeof(leaf_spki_hash)); |
| 2023 have_leaf_spki_hash = true; |
| 2024 } |
| 2025 |
| 2026 if (VerifySignature(pubkey, sig, base::StringPiece( |
| 2027 reinterpret_cast<const char*>(leaf_spki_hash), |
| 2028 sizeof(leaf_spki_hash)))) { |
| 2029 SHA1Fingerprint fpr; |
| 2030 base::SHA1HashBytes( |
| 2031 reinterpret_cast<const uint8*>(pubkey.data()), |
| 2032 pubkey.size(), |
| 2033 fpr.data); |
| 2034 out_pub_key_hash->push_back(fpr); |
| 2035 have_parsed_a_key = true; |
| 2036 } |
| 2037 } |
| 2038 |
| 2039 return have_parsed_a_key; |
| 2040 } |
| 2041 |
| 2042 // This function converts the binary hashes, which we store in |
| 2043 // |enabled_hosts_|, to a base64 string which we can include in a JSON file. |
| 2044 static std::string HashedDomainToExternalString(const std::string& hashed) { |
| 2045 std::string out; |
| 2046 CHECK(base::Base64Encode(hashed, &out)); |
| 2047 return out; |
| 2048 } |
| 2049 |
| 2050 // This inverts |HashedDomainToExternalString|, above. It turns an external |
| 2051 // string (from a JSON file) into an internal (binary) string. |
| 2052 static std::string ExternalStringToHashedDomain(const std::string& external) { |
| 2053 std::string out; |
| 2054 if (!base::Base64Decode(external, &out) || |
| 2055 out.size() != crypto::kSHA256Length) { |
| 2056 return std::string(); |
| 2057 } |
| 2058 |
| 2059 return out; |
| 2060 } |
| 2061 |
| 2062 static ListValue* SPKIHashesToListValue(const FingerprintVector& hashes) { |
| 2063 ListValue* pins = new ListValue; |
| 2064 |
| 2065 for (FingerprintVector::const_iterator i = hashes.begin(); |
| 2066 i != hashes.end(); ++i) { |
| 2067 std::string hash_str(reinterpret_cast<const char*>(i->data), |
| 2068 sizeof(i->data)); |
| 2069 std::string b64; |
| 2070 base::Base64Encode(hash_str, &b64); |
| 2071 pins->Append(new StringValue("sha1/" + b64)); |
| 2072 } |
| 2073 |
| 2074 return pins; |
| 2075 } |
| 2076 |
| 2077 bool TransportSecurityState::Serialise(std::string* output) { |
| 2078 DCHECK(CalledOnValidThread()); |
| 2079 |
| 2080 DictionaryValue toplevel; |
| 2081 base::Time now = base::Time::Now(); |
| 2082 for (std::map<std::string, DomainState>::const_iterator |
| 2083 i = enabled_hosts_.begin(); i != enabled_hosts_.end(); ++i) { |
| 2084 DictionaryValue* state = new DictionaryValue; |
| 2085 state->SetBoolean("include_subdomains", i->second.include_subdomains); |
| 2086 state->SetDouble("created", i->second.created.ToDoubleT()); |
| 2087 state->SetDouble("expiry", i->second.expiry.ToDoubleT()); |
| 2088 state->SetDouble("dynamic_spki_hashes_expiry", |
| 2089 i->second.dynamic_spki_hashes_expiry.ToDoubleT()); |
| 2090 |
| 2091 switch (i->second.mode) { |
| 2092 case DomainState::MODE_STRICT: |
| 2093 state->SetString("mode", "strict"); |
| 2094 break; |
| 2095 case DomainState::MODE_SPDY_ONLY: |
| 2096 state->SetString("mode", "spdy-only"); |
| 2097 break; |
| 2098 case DomainState::MODE_PINNING_ONLY: |
| 2099 state->SetString("mode", "pinning-only"); |
| 2100 break; |
| 2101 default: |
| 2102 NOTREACHED() << "DomainState with unknown mode"; |
| 2103 delete state; |
| 2104 continue; |
| 2105 } |
| 2106 |
| 2107 state->Set("preloaded_spki_hashes", |
| 2108 SPKIHashesToListValue(i->second.preloaded_spki_hashes)); |
| 2109 |
| 2110 if (now < i->second.dynamic_spki_hashes_expiry) { |
| 2111 state->Set("dynamic_spki_hashes", |
| 2112 SPKIHashesToListValue(i->second.dynamic_spki_hashes)); |
| 2113 } |
| 2114 |
| 2115 toplevel.Set(HashedDomainToExternalString(i->first), state); |
| 2116 } |
| 2117 |
| 2118 base::JSONWriter::WriteWithOptions(&toplevel, |
| 2119 base::JSONWriter::OPTIONS_PRETTY_PRINT, |
| 2120 output); |
| 2121 return true; |
| 2122 } |
| 2123 |
| 2124 bool TransportSecurityState::LoadEntries(const std::string& input, |
| 2125 bool* dirty) { |
| 2126 DCHECK(CalledOnValidThread()); |
| 2127 |
| 2128 enabled_hosts_.clear(); |
| 2129 return Deserialise(input, dirty, &enabled_hosts_); |
| 2130 } |
| 2131 |
| 2132 static bool AddHash(const std::string& type_and_base64, |
| 2133 FingerprintVector* out) { |
| 2134 SHA1Fingerprint hash; |
| 2135 |
| 2136 if (!TransportSecurityState::ParsePin(type_and_base64, &hash)) |
| 2137 return false; |
| 2138 |
| 2139 out->push_back(hash); |
| 2140 return true; |
| 2141 } |
| 2142 |
| 2143 static void SPKIHashesFromListValue(FingerprintVector* hashes, |
| 2144 const ListValue& pins) { |
| 2145 size_t num_pins = pins.GetSize(); |
| 2146 for (size_t i = 0; i < num_pins; ++i) { |
| 2147 std::string type_and_base64; |
| 2148 if (pins.GetString(i, &type_and_base64)) |
| 2149 AddHash(type_and_base64, hashes); |
| 2150 } |
| 2151 } |
| 2152 |
| 2153 // static |
| 2154 bool TransportSecurityState::Deserialise( |
| 2155 const std::string& input, |
| 2156 bool* dirty, |
| 2157 std::map<std::string, DomainState>* out) { |
| 2158 scoped_ptr<Value> value( |
| 2159 base::JSONReader::Read(input, false /* do not allow trailing commas */)); |
| 2160 if (!value.get() || !value->IsType(Value::TYPE_DICTIONARY)) |
| 2161 return false; |
| 2162 |
| 2163 DictionaryValue* dict_value = reinterpret_cast<DictionaryValue*>(value.get()); |
| 2164 const base::Time current_time(base::Time::Now()); |
| 2165 bool dirtied = false; |
| 2166 |
| 2167 for (DictionaryValue::key_iterator i = dict_value->begin_keys(); |
| 2168 i != dict_value->end_keys(); ++i) { |
| 2169 DictionaryValue* state; |
| 2170 if (!dict_value->GetDictionaryWithoutPathExpansion(*i, &state)) |
| 2171 continue; |
| 2172 |
| 2173 bool include_subdomains; |
| 2174 std::string mode_string; |
| 2175 double created; |
| 2176 double expiry; |
| 2177 double dynamic_spki_hashes_expiry = 0.0; |
| 2178 |
| 2179 if (!state->GetBoolean("include_subdomains", &include_subdomains) || |
| 2180 !state->GetString("mode", &mode_string) || |
| 2181 !state->GetDouble("expiry", &expiry)) { |
| 2182 continue; |
| 2183 } |
| 2184 |
| 2185 // Don't fail if this key is not present. |
| 2186 (void) state->GetDouble("dynamic_spki_hashes_expiry", |
| 2187 &dynamic_spki_hashes_expiry); |
| 2188 |
| 2189 ListValue* pins_list = NULL; |
| 2190 FingerprintVector preloaded_spki_hashes; |
| 2191 if (state->GetList("preloaded_spki_hashes", &pins_list)) |
| 2192 SPKIHashesFromListValue(&preloaded_spki_hashes, *pins_list); |
| 2193 |
| 2194 FingerprintVector dynamic_spki_hashes; |
| 2195 if (state->GetList("dynamic_spki_hashes", &pins_list)) |
| 2196 SPKIHashesFromListValue(&dynamic_spki_hashes, *pins_list); |
| 2197 |
| 2198 DomainState::Mode mode; |
| 2199 if (mode_string == "strict") { |
| 2200 mode = DomainState::MODE_STRICT; |
| 2201 } else if (mode_string == "spdy-only") { |
| 2202 mode = DomainState::MODE_SPDY_ONLY; |
| 2203 } else if (mode_string == "pinning-only") { |
| 2204 mode = DomainState::MODE_PINNING_ONLY; |
| 2205 } else { |
| 2206 LOG(WARNING) << "Unknown TransportSecurityState mode string found: " |
| 2207 << mode_string; |
| 2208 continue; |
| 2209 } |
| 2210 |
| 2211 base::Time expiry_time = base::Time::FromDoubleT(expiry); |
| 2212 base::Time dynamic_spki_hashes_expiry_time = |
| 2213 base::Time::FromDoubleT(dynamic_spki_hashes_expiry); |
| 2214 base::Time created_time; |
| 2215 if (state->GetDouble("created", &created)) { |
| 2216 created_time = base::Time::FromDoubleT(created); |
| 2217 } else { |
| 2218 // We're migrating an old entry with no creation date. Make sure we |
| 2219 // write the new date back in a reasonable time frame. |
| 2220 dirtied = true; |
| 2221 created_time = base::Time::Now(); |
| 2222 } |
| 2223 |
| 2224 if (expiry_time <= current_time && |
| 2225 dynamic_spki_hashes_expiry_time <= current_time) { |
| 2226 // Make sure we dirty the state if we drop an entry. |
| 2227 dirtied = true; |
| 2228 continue; |
| 2229 } |
| 2230 |
| 2231 std::string hashed = ExternalStringToHashedDomain(*i); |
| 2232 if (hashed.empty()) { |
| 2233 dirtied = true; |
| 2234 continue; |
| 2235 } |
| 2236 |
| 2237 DomainState new_state; |
| 2238 new_state.mode = mode; |
| 2239 new_state.created = created_time; |
| 2240 new_state.expiry = expiry_time; |
| 2241 new_state.include_subdomains = include_subdomains; |
| 2242 new_state.preloaded_spki_hashes = preloaded_spki_hashes; |
| 2243 new_state.dynamic_spki_hashes = dynamic_spki_hashes; |
| 2244 new_state.dynamic_spki_hashes_expiry = dynamic_spki_hashes_expiry_time; |
| 2245 (*out)[hashed] = new_state; |
| 2246 } |
| 2247 |
| 2248 *dirty = dirtied; |
| 2249 return true; |
| 2250 } |
| 2251 |
| 2252 TransportSecurityState::~TransportSecurityState() { |
| 2253 } |
| 2254 |
| 2255 void TransportSecurityState::DirtyNotify() { |
| 2256 DCHECK(CalledOnValidThread()); |
| 2257 |
| 2258 if (delegate_) |
| 2259 delegate_->StateIsDirty(this); |
| 2260 } |
| 2261 |
| 2262 // static |
| 2263 std::string TransportSecurityState::CanonicalizeHost(const std::string& host) { |
| 2264 // We cannot perform the operations as detailed in the spec here as |host| |
| 2265 // has already undergone IDN processing before it reached us. Thus, we check |
| 2266 // that there are no invalid characters in the host and lowercase the result. |
| 2267 |
| 2268 std::string new_host; |
| 2269 if (!DNSDomainFromDot(host, &new_host)) { |
| 2270 // DNSDomainFromDot can fail if any label is > 63 bytes or if the whole |
| 2271 // name is >255 bytes. However, search terms can have those properties. |
| 2272 return std::string(); |
| 2273 } |
| 2274 |
| 2275 for (size_t i = 0; new_host[i]; i += new_host[i] + 1) { |
| 2276 const unsigned label_length = static_cast<unsigned>(new_host[i]); |
| 2277 if (!label_length) |
| 2278 break; |
| 2279 |
| 2280 for (size_t j = 0; j < label_length; ++j) { |
| 2281 // RFC 3490, 4.1, step 3 |
| 2282 if (!IsSTD3ASCIIValidCharacter(new_host[i + 1 + j])) |
| 2283 return std::string(); |
| 2284 |
| 2285 new_host[i + 1 + j] = tolower(new_host[i + 1 + j]); |
| 2286 } |
| 2287 |
| 2288 // step 3(b) |
| 2289 if (new_host[i + 1] == '-' || |
| 2290 new_host[i + label_length] == '-') { |
| 2291 return std::string(); |
| 2292 } |
| 2293 } |
| 2294 |
| 2295 return new_host; |
| 2296 } |
| 2297 |
| 2298 // |ReportUMAOnPinFailure| uses these to report which domain was associated |
| 2299 // with the public key pinning failure. |
| 2300 // |
| 2301 // DO NOT CHANGE THE ORDERING OF THESE NAMES OR REMOVE ANY OF THEM. Add new |
| 2302 // domains at the END of the listing (but before DOMAIN_NUM_EVENTS). |
| 2303 enum SecondLevelDomainName { |
| 2304 DOMAIN_NOT_PINNED, |
| 2305 |
| 2306 DOMAIN_GOOGLE_COM, |
| 2307 DOMAIN_ANDROID_COM, |
| 2308 DOMAIN_GOOGLE_ANALYTICS_COM, |
| 2309 DOMAIN_GOOGLEPLEX_COM, |
| 2310 DOMAIN_YTIMG_COM, |
| 2311 DOMAIN_GOOGLEUSERCONTENT_COM, |
| 2312 DOMAIN_YOUTUBE_COM, |
| 2313 DOMAIN_GOOGLEAPIS_COM, |
| 2314 DOMAIN_GOOGLEADSERVICES_COM, |
| 2315 DOMAIN_GOOGLECODE_COM, |
| 2316 DOMAIN_APPSPOT_COM, |
| 2317 DOMAIN_GOOGLESYNDICATION_COM, |
| 2318 DOMAIN_DOUBLECLICK_NET, |
| 2319 DOMAIN_GSTATIC_COM, |
| 2320 DOMAIN_GMAIL_COM, |
| 2321 DOMAIN_GOOGLEMAIL_COM, |
| 2322 DOMAIN_GOOGLEGROUPS_COM, |
| 2323 |
| 2324 DOMAIN_TORPROJECT_ORG, |
| 2325 |
| 2326 DOMAIN_TWITTER_COM, |
| 2327 DOMAIN_TWIMG_COM, |
| 2328 |
| 2329 DOMAIN_AKAMAIHD_NET, |
| 2330 |
| 2331 // Boundary value for UMA_HISTOGRAM_ENUMERATION: |
| 2332 DOMAIN_NUM_EVENTS |
| 2333 }; |
| 2334 |
| 2335 // PublicKeyPins contains a number of SubjectPublicKeyInfo hashes for a site. |
| 2336 // The validated certificate chain for the site must not include any of |
| 2337 // |excluded_hashes| and must include one or more of |required_hashes|. |
| 2338 struct PublicKeyPins { |
| 2339 const char* const* required_hashes; |
| 2340 const char* const* excluded_hashes; |
| 2341 }; |
| 2342 |
| 2343 struct HSTSPreload { |
| 2344 uint8 length; |
| 2345 bool include_subdomains; |
| 2346 char dns_name[30]; |
| 2347 bool https_required; |
| 2348 PublicKeyPins pins; |
| 2349 SecondLevelDomainName second_level_domain_name; |
| 2350 }; |
| 2351 |
| 2352 static bool HasPreload(const struct HSTSPreload* entries, size_t num_entries, |
| 2353 const std::string& canonicalized_host, size_t i, |
| 2354 TransportSecurityState::DomainState* out, bool* ret) { |
| 2355 for (size_t j = 0; j < num_entries; j++) { |
| 2356 if (entries[j].length == canonicalized_host.size() - i && |
| 2357 memcmp(entries[j].dns_name, &canonicalized_host[i], |
| 2358 entries[j].length) == 0) { |
| 2359 if (!entries[j].include_subdomains && i != 0) { |
| 2360 *ret = false; |
| 2361 } else { |
| 2362 out->include_subdomains = entries[j].include_subdomains; |
| 2363 *ret = true; |
| 2364 if (!entries[j].https_required) |
| 2365 out->mode = TransportSecurityState::DomainState::MODE_PINNING_ONLY; |
| 2366 if (entries[j].pins.required_hashes) { |
| 2367 const char* const* hash = entries[j].pins.required_hashes; |
| 2368 while (*hash) { |
| 2369 bool ok = AddHash(*hash, &out->preloaded_spki_hashes); |
| 2370 DCHECK(ok) << " failed to parse " << *hash; |
| 2371 hash++; |
| 2372 } |
| 2373 } |
| 2374 if (entries[j].pins.excluded_hashes) { |
| 2375 const char* const* hash = entries[j].pins.excluded_hashes; |
| 2376 while (*hash) { |
| 2377 bool ok = AddHash(*hash, &out->bad_preloaded_spki_hashes); |
| 2378 DCHECK(ok) << " failed to parse " << *hash; |
| 2379 hash++; |
| 2380 } |
| 2381 } |
| 2382 } |
| 2383 return true; |
| 2384 } |
| 2385 } |
| 2386 return false; |
| 2387 } |
| 1248 | 2388 |
| 1249 // kNoRejectedPublicKeys is a placeholder for when no public keys are rejected. | 2389 // kNoRejectedPublicKeys is a placeholder for when no public keys are rejected. |
| 1250 static const char* const kNoRejectedPublicKeys[] = { | 2390 static const char* const kNoRejectedPublicKeys[] = { |
| 1251 NULL, | 2391 NULL, |
| 1252 }; | 2392 }; |
| 1253 | 2393 |
| 1254 static const char* const kTestAcceptableCerts[] = { | |
| 1255 kSPKIHash_TestSPKI, | |
| 1256 NULL, | |
| 1257 }; | |
| 1258 #define kTestPins { \ | |
| 1259 kTestAcceptableCerts, \ | |
| 1260 kNoRejectedPublicKeys, \ | |
| 1261 } | |
| 1262 | |
| 1263 static const char* const kGoogleAcceptableCerts[] = { | 2394 static const char* const kGoogleAcceptableCerts[] = { |
| 1264 kSPKIHash_VeriSignClass3, | 2395 kSPKIHash_VeriSignClass3, |
| 1265 kSPKIHash_VeriSignClass3_G3, | 2396 kSPKIHash_VeriSignClass3_G3, |
| 1266 kSPKIHash_Google1024, | 2397 kSPKIHash_Google1024, |
| 1267 kSPKIHash_Google2048, | 2398 kSPKIHash_Google2048, |
| 1268 kSPKIHash_EquifaxSecureCA, | 2399 kSPKIHash_EquifaxSecureCA, |
| 1269 NULL, | 2400 NULL, |
| 1270 }; | 2401 }; |
| 1271 static const char* const kGoogleRejectedCerts[] = { | 2402 static const char* const kGoogleRejectedCerts[] = { |
| 1272 kSPKIHash_Aetna, | 2403 kSPKIHash_Aetna, |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1313 kSPKIHash_GeoTrustPrimary_G2, | 2444 kSPKIHash_GeoTrustPrimary_G2, |
| 1314 kSPKIHash_GeoTrustPrimary_G3, | 2445 kSPKIHash_GeoTrustPrimary_G3, |
| 1315 kSPKIHash_Twitter1, | 2446 kSPKIHash_Twitter1, |
| 1316 NULL, | 2447 NULL, |
| 1317 }; | 2448 }; |
| 1318 #define kTwitterComPins { \ | 2449 #define kTwitterComPins { \ |
| 1319 kTwitterComAcceptableCerts, \ | 2450 kTwitterComAcceptableCerts, \ |
| 1320 kNoRejectedPublicKeys, \ | 2451 kNoRejectedPublicKeys, \ |
| 1321 } | 2452 } |
| 1322 | 2453 |
| 2454 // kTwitterCDNAcceptableCerts are the set of public keys valid for Twitter's |
| 2455 // CDNs, which includes all the keys from kTwitterComAcceptableCerts. |
| 1323 static const char* const kTwitterCDNAcceptableCerts[] = { | 2456 static const char* const kTwitterCDNAcceptableCerts[] = { |
| 1324 kSPKIHash_VeriSignClass1, | 2457 kSPKIHash_VeriSignClass1, |
| 1325 kSPKIHash_VeriSignClass3, | 2458 kSPKIHash_VeriSignClass3, |
| 1326 kSPKIHash_VeriSignClass3_G4, | 2459 kSPKIHash_VeriSignClass3_G4, |
| 1327 kSPKIHash_VeriSignClass4_G3, | 2460 kSPKIHash_VeriSignClass4_G3, |
| 1328 kSPKIHash_VeriSignClass3_G3, | 2461 kSPKIHash_VeriSignClass3_G3, |
| 1329 kSPKIHash_VeriSignClass1_G3, | 2462 kSPKIHash_VeriSignClass1_G3, |
| 1330 kSPKIHash_VeriSignClass2_G3, | 2463 kSPKIHash_VeriSignClass2_G3, |
| 1331 kSPKIHash_VeriSignClass3_G2, | 2464 kSPKIHash_VeriSignClass3_G2, |
| 1332 kSPKIHash_VeriSignClass2_G2, | 2465 kSPKIHash_VeriSignClass2_G2, |
| 1333 kSPKIHash_VeriSignClass3_G5, | 2466 kSPKIHash_VeriSignClass3_G5, |
| 1334 kSPKIHash_VeriSignUniversal, | 2467 kSPKIHash_VeriSignUniversal, |
| 1335 kSPKIHash_GeoTrustGlobal, | 2468 kSPKIHash_GeoTrustGlobal, |
| 1336 kSPKIHash_GeoTrustGlobal2, | 2469 kSPKIHash_GeoTrustGlobal2, |
| 1337 kSPKIHash_GeoTrustUniversal, | 2470 kSPKIHash_GeoTrustUniversal, |
| 1338 kSPKIHash_GeoTrustUniversal2, | 2471 kSPKIHash_GeoTrustUniversal2, |
| 1339 kSPKIHash_GeoTrustPrimary, | 2472 kSPKIHash_GeoTrustPrimary, |
| 1340 kSPKIHash_GeoTrustPrimary_G2, | 2473 kSPKIHash_GeoTrustPrimary_G2, |
| 1341 kSPKIHash_GeoTrustPrimary_G3, | 2474 kSPKIHash_GeoTrustPrimary_G3, |
| 1342 kSPKIHash_Twitter1, | 2475 kSPKIHash_Twitter1, |
| 2476 |
| 1343 kSPKIHash_Entrust_2048, | 2477 kSPKIHash_Entrust_2048, |
| 1344 kSPKIHash_Entrust_EV, | 2478 kSPKIHash_Entrust_EV, |
| 1345 kSPKIHash_Entrust_G2, | 2479 kSPKIHash_Entrust_G2, |
| 1346 kSPKIHash_Entrust_SSL, | 2480 kSPKIHash_Entrust_SSL, |
| 1347 kSPKIHash_AAACertificateServices, | 2481 kSPKIHash_AAACertificateServices, |
| 1348 kSPKIHash_AddTrustClass1CARoot, | 2482 kSPKIHash_AddTrustClass1CARoot, |
| 1349 kSPKIHash_AddTrustExternalCARoot, | 2483 kSPKIHash_AddTrustExternalCARoot, |
| 1350 kSPKIHash_AddTrustPublicCARoot, | 2484 kSPKIHash_AddTrustPublicCARoot, |
| 1351 kSPKIHash_AddTrustQualifiedCARoot, | 2485 kSPKIHash_AddTrustQualifiedCARoot, |
| 1352 kSPKIHash_COMODOCertificationAuthority, | 2486 kSPKIHash_COMODOCertificationAuthority, |
| 1353 kSPKIHash_SecureCertificateServices, | 2487 kSPKIHash_SecureCertificateServices, |
| 1354 kSPKIHash_TrustedCertificateServices, | 2488 kSPKIHash_TrustedCertificateServices, |
| 1355 kSPKIHash_UTNDATACorpSGC, | 2489 kSPKIHash_UTNDATACorpSGC, |
| 1356 kSPKIHash_UTNUSERFirstClientAuthenticationandEmail, | 2490 kSPKIHash_UTNUSERFirstClientAuthenticationandEmail, |
| 1357 kSPKIHash_UTNUSERFirstHardware, | 2491 kSPKIHash_UTNUSERFirstHardware, |
| 1358 kSPKIHash_UTNUSERFirstObject, | 2492 kSPKIHash_UTNUSERFirstObject, |
| 1359 kSPKIHash_GTECyberTrustGlobalRoot, | 2493 kSPKIHash_GTECyberTrustGlobalRoot, |
| 1360 NULL, | 2494 NULL, |
| 1361 }; | 2495 }; |
| 1362 #define kTwitterCDNPins { \ | 2496 #define kTwitterCDNPins { \ |
| 1363 kTwitterCDNAcceptableCerts, \ | 2497 kTwitterCDNAcceptableCerts, \ |
| 1364 kNoRejectedPublicKeys, \ | 2498 kNoRejectedPublicKeys, \ |
| 1365 } | 2499 } |
| 1366 | 2500 |
| 1367 #define kNoPins {\ | 2501 // kTestAcceptableCerts doesn't actually match any public keys and is used |
| 2502 // with "pinningtest.appspot.com", below, to test if pinning is active. |
| 2503 static const char* const kTestAcceptableCerts[] = { |
| 2504 "sha1/AAAAAAAAAAAAAAAAAAAAAAAAAAA=", |
| 2505 NULL, |
| 2506 }; |
| 2507 #define kTestPins { \ |
| 2508 kTestAcceptableCerts, \ |
| 2509 kNoRejectedPublicKeys, \ |
| 2510 } |
| 2511 |
| 2512 #define kNoPins { \ |
| 1368 NULL, NULL, \ | 2513 NULL, NULL, \ |
| 1369 } | 2514 } |
| 1370 | 2515 |
| 2516 #if defined(OS_CHROMEOS) |
| 2517 static const bool kTwitterHSTS = true; |
| 2518 #else |
| 2519 static const bool kTwitterHSTS = false; |
| 2520 #endif |
| 2521 |
| 2522 // In the medium term this list is likely to just be hardcoded here. This |
| 2523 // slightly odd form removes the need for additional relocations records. |
| 1371 static const struct HSTSPreload kPreloadedSTS[] = { | 2524 static const struct HSTSPreload kPreloadedSTS[] = { |
| 2525 // (*.)google.com, iff using SSL must use an acceptable certificate. |
| 2526 {12, true, "\006google\003com", false, kGooglePins, DOMAIN_GOOGLE_COM }, |
| 1372 {25, true, "\013pinningtest\007appspot\003com", false, kTestPins, DOMAIN_APPSP
OT_COM }, | 2527 {25, true, "\013pinningtest\007appspot\003com", false, kTestPins, DOMAIN_APPSP
OT_COM }, |
| 1373 {12, true, "\006google\003com", false, kGooglePins, DOMAIN_GOOGLE_COM }, | 2528 // Now we force HTTPS for subtrees of google.com. |
| 1374 {19, true, "\006health\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM
}, | 2529 {19, true, "\006health\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM
}, |
| 1375 {21, true, "\010checkout\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_C
OM }, | 2530 {21, true, "\010checkout\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_C
OM }, |
| 1376 {19, true, "\006chrome\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM
}, | 2531 {19, true, "\006chrome\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM
}, |
| 1377 {17, true, "\004docs\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM }
, | 2532 {17, true, "\004docs\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM }
, |
| 1378 {18, true, "\005sites\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM
}, | 2533 {18, true, "\005sites\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM
}, |
| 1379 {25, true, "\014spreadsheets\006google\003com", true, kGooglePins, DOMAIN_GOOG
LE_COM }, | 2534 {25, true, "\014spreadsheets\006google\003com", true, kGooglePins, DOMAIN_GOOG
LE_COM }, |
| 1380 {22, false, "\011appengine\006google\003com", true, kGooglePins, DOMAIN_GOOGLE
_COM }, | 2535 {22, false, "\011appengine\006google\003com", true, kGooglePins, DOMAIN_GOOGLE
_COM }, |
| 1381 {22, true, "\011encrypted\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_
COM }, | 2536 {22, true, "\011encrypted\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_
COM }, |
| 1382 {21, true, "\010accounts\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_C
OM }, | 2537 {21, true, "\010accounts\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_C
OM }, |
| 1383 {21, true, "\010profiles\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_C
OM }, | 2538 {21, true, "\010profiles\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_C
OM }, |
| 1384 {17, true, "\004mail\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM }
, | 2539 {17, true, "\004mail\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM }
, |
| 1385 {23, true, "\012talkgadget\006google\003com", true, kGooglePins, DOMAIN_GOOGLE
_COM }, | 2540 {23, true, "\012talkgadget\006google\003com", true, kGooglePins, DOMAIN_GOOGLE
_COM }, |
| 1386 {17, true, "\004talk\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM }
, | 2541 {17, true, "\004talk\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM }
, |
| 1387 {29, true, "\020hostedtalkgadget\006google\003com", true, kGooglePins, DOMAIN_
GOOGLE_COM }, | 2542 {29, true, "\020hostedtalkgadget\006google\003com", true, kGooglePins, DOMAIN_
GOOGLE_COM }, |
| 1388 {17, true, "\004plus\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM }
, | 2543 {17, true, "\004plus\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM }
, |
| 2544 // Other Google-related domains that must use HTTPS. |
| 1389 {20, true, "\006market\007android\003com", true, kGooglePins, DOMAIN_ANDROID_C
OM }, | 2545 {20, true, "\006market\007android\003com", true, kGooglePins, DOMAIN_ANDROID_C
OM }, |
| 1390 {26, true, "\003ssl\020google-analytics\003com", true, kGooglePins, DOMAIN_GOO
GLE_ANALYTICS_COM }, | 2546 {26, true, "\003ssl\020google-analytics\003com", true, kGooglePins, DOMAIN_GOO
GLE_ANALYTICS_COM }, |
| 1391 {18, true, "\005drive\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM
}, | 2547 {18, true, "\005drive\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM
}, |
| 1392 {16, true, "\012googleplex\003com", true, kGooglePins, DOMAIN_GOOGLEPLEX_COM }
, | 2548 {16, true, "\012googleplex\003com", true, kGooglePins, DOMAIN_GOOGLEPLEX_COM }
, |
| 1393 {19, true, "\006groups\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM
}, | 2549 {19, true, "\006groups\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM
}, |
| 1394 {17, true, "\004apis\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM }
, | 2550 {17, true, "\004apis\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM }
, |
| 1395 {23, true, "\005chart\004apis\006google\003com", false, kGooglePins, DOMAIN_GO
OGLE_COM }, | 2551 // chart.apis.google.com is *not* HSTS because the certificate doesn't match |
| 2552 // and there are lots of links out there that still use the name. The correct |
| 2553 // hostname for this is chart.googleapis.com. |
| 2554 {23, true, "\005chart\004apis\006google\003com", false, kGooglePins, DOMAIN_GO
OGLE_COM}, |
| 2555 |
| 2556 // Other Google-related domains that must use an acceptable certificate |
| 2557 // iff using SSL. |
| 1396 {11, true, "\005ytimg\003com", false, kGooglePins, DOMAIN_YTIMG_COM }, | 2558 {11, true, "\005ytimg\003com", false, kGooglePins, DOMAIN_YTIMG_COM }, |
| 1397 {23, true, "\021googleusercontent\003com", false, kGooglePins, DOMAIN_GOOGLEUS
ERCONTENT_COM }, | 2559 {23, true, "\021googleusercontent\003com", false, kGooglePins, DOMAIN_GOOGLEUS
ERCONTENT_COM }, |
| 1398 {13, true, "\007youtube\003com", false, kGooglePins, DOMAIN_YOUTUBE_COM }, | 2560 {13, true, "\007youtube\003com", false, kGooglePins, DOMAIN_YOUTUBE_COM }, |
| 1399 {16, true, "\012googleapis\003com", false, kGooglePins, DOMAIN_GOOGLEAPIS_COM
}, | 2561 {16, true, "\012googleapis\003com", false, kGooglePins, DOMAIN_GOOGLEAPIS_COM
}, |
| 1400 {22, true, "\020googleadservices\003com", false, kGooglePins, DOMAIN_GOOGLEADS
ERVICES_COM }, | 2562 {22, true, "\020googleadservices\003com", false, kGooglePins, DOMAIN_GOOGLEADS
ERVICES_COM }, |
| 1401 {16, true, "\012googlecode\003com", false, kGooglePins, DOMAIN_GOOGLECODE_COM
}, | 2563 {16, true, "\012googlecode\003com", false, kGooglePins, DOMAIN_GOOGLECODE_COM
}, |
| 1402 {13, true, "\007appspot\003com", false, kGooglePins, DOMAIN_APPSPOT_COM }, | 2564 {13, true, "\007appspot\003com", false, kGooglePins, DOMAIN_APPSPOT_COM }, |
| 1403 {23, true, "\021googlesyndication\003com", false, kGooglePins, DOMAIN_GOOGLESY
NDICATION_COM }, | 2565 {23, true, "\021googlesyndication\003com", false, kGooglePins, DOMAIN_GOOGLESY
NDICATION_COM }, |
| 1404 {17, true, "\013doubleclick\003net", false, kGooglePins, DOMAIN_DOUBLECLICK_NE
T }, | 2566 {17, true, "\013doubleclick\003net", false, kGooglePins, DOMAIN_DOUBLECLICK_NE
T }, |
| 1405 {17, true, "\003ssl\007gstatic\003com", false, kGooglePins, DOMAIN_GSTATIC_COM
}, | 2567 {17, true, "\003ssl\007gstatic\003com", false, kGooglePins, DOMAIN_GSTATIC_COM
}, |
| 2568 // Exclude the learn.doubleclick.net subdomain because it uses a different |
| 2569 // CA. |
| 1406 {23, true, "\005learn\013doubleclick\003net", false, kNoPins, DOMAIN_NOT_PINNE
D }, | 2570 {23, true, "\005learn\013doubleclick\003net", false, kNoPins, DOMAIN_NOT_PINNE
D }, |
| 2571 // Now we force HTTPS for other sites that have requested it. |
| 1407 {16, false, "\003www\006paypal\003com", true, kNoPins, DOMAIN_NOT_PINNED }, | 2572 {16, false, "\003www\006paypal\003com", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1408 {16, false, "\003www\006elanex\003biz", true, kNoPins, DOMAIN_NOT_PINNED }, | 2573 {16, false, "\003www\006elanex\003biz", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1409 {12, true, "\006jottit\003com", true, kNoPins, DOMAIN_NOT_PINNED }, | 2574 {12, true, "\006jottit\003com", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1410 {19, true, "\015sunshinepress\003org", true, kNoPins, DOMAIN_NOT_PINNED }, | 2575 {19, true, "\015sunshinepress\003org", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1411 {21, false, "\003www\013noisebridge\003net", true, kNoPins, DOMAIN_NOT_PINNED
}, | 2576 {21, false, "\003www\013noisebridge\003net", true, kNoPins, DOMAIN_NOT_PINNED
}, |
| 1412 {10, false, "\004neg9\003org", true, kNoPins, DOMAIN_NOT_PINNED }, | 2577 {10, false, "\004neg9\003org", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1413 {12, true, "\006riseup\003net", true, kNoPins, DOMAIN_NOT_PINNED }, | 2578 {12, true, "\006riseup\003net", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1414 {11, false, "\006factor\002cc", true, kNoPins, DOMAIN_NOT_PINNED }, | 2579 {11, false, "\006factor\002cc", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1415 {22, false, "\007members\010mayfirst\003org", true, kNoPins, DOMAIN_NOT_PINNED
}, | 2580 {22, false, "\007members\010mayfirst\003org", true, kNoPins, DOMAIN_NOT_PINNED
}, |
| 1416 {22, false, "\007support\010mayfirst\003org", true, kNoPins, DOMAIN_NOT_PINNED
}, | 2581 {22, false, "\007support\010mayfirst\003org", true, kNoPins, DOMAIN_NOT_PINNED
}, |
| 1417 {17, false, "\002id\010mayfirst\003org", true, kNoPins, DOMAIN_NOT_PINNED }, | 2582 {17, false, "\002id\010mayfirst\003org", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1418 {20, false, "\005lists\010mayfirst\003org", true, kNoPins, DOMAIN_NOT_PINNED }
, | 2583 {20, false, "\005lists\010mayfirst\003org", true, kNoPins, DOMAIN_NOT_PINNED }
, |
| 1419 {19, true, "\015splendidbacon\003com", true, kNoPins, DOMAIN_NOT_PINNED }, | 2584 {19, true, "\015splendidbacon\003com", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1420 {28, false, "\016aladdinschools\007appspot\003com", true, kNoPins, DOMAIN_NOT_
PINNED }, | 2585 {28, false, "\016aladdinschools\007appspot\003com", true, kNoPins, DOMAIN_NOT_
PINNED }, |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1453 {10, false, "\004kyps\003net", true, kNoPins, DOMAIN_NOT_PINNED }, | 2618 {10, false, "\004kyps\003net", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1454 {14, false, "\003www\004kyps\003net", true, kNoPins, DOMAIN_NOT_PINNED }, | 2619 {14, false, "\003www\004kyps\003net", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1455 {17, true, "\003app\007recurly\003com", true, kNoPins, DOMAIN_NOT_PINNED }, | 2620 {17, true, "\003app\007recurly\003com", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1456 {17, true, "\003api\007recurly\003com", true, kNoPins, DOMAIN_NOT_PINNED }, | 2621 {17, true, "\003api\007recurly\003com", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1457 {13, false, "\007greplin\003com", true, kNoPins, DOMAIN_NOT_PINNED }, | 2622 {13, false, "\007greplin\003com", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1458 {17, false, "\003www\007greplin\003com", true, kNoPins, DOMAIN_NOT_PINNED }, | 2623 {17, false, "\003www\007greplin\003com", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1459 {27, true, "\006luneta\016nearbuysystems\003com", true, kNoPins, DOMAIN_NOT_PI
NNED }, | 2624 {27, true, "\006luneta\016nearbuysystems\003com", true, kNoPins, DOMAIN_NOT_PI
NNED }, |
| 1460 {12, true, "\006ubertt\003org", true, kNoPins, DOMAIN_NOT_PINNED }, | 2625 {12, true, "\006ubertt\003org", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1461 {9, true, "\004pixi\002me", true, kNoPins, DOMAIN_NOT_PINNED }, | 2626 {9, true, "\004pixi\002me", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1462 {14, true, "\010grepular\003com", true, kNoPins, DOMAIN_NOT_PINNED }, | 2627 {14, true, "\010grepular\003com", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1463 {16, false, "\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED }, | 2628 {16, false , "\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1464 {20, false, "\003www\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED }
, | 2629 {20, false , "\003www\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED
}, |
| 1465 {26, false, "\011developer\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PI
NNED }, | 2630 {26, false , "\011developer\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_P
INNED }, |
| 1466 {30, false, "\003www\011developer\012mydigipass\003com", true, kNoPins, DOMAIN
_NOT_PINNED }, | 2631 {30, false , "\003www\011developer\012mydigipass\003com", true, kNoPins, DOMAI
N_NOT_PINNED }, |
| 1467 {24, false, "\007sandbox\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINN
ED }, | 2632 {24, false , "\007sandbox\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PIN
NED }, |
| 1468 {28, false, "\003www\007sandbox\012mydigipass\003com", true, kNoPins, DOMAIN_N
OT_PINNED }, | 2633 {28, false , "\003www\007sandbox\012mydigipass\003com", true, kNoPins, DOMAIN_
NOT_PINNED }, |
| 1469 {12, true, "\006crypto\003cat", true, kNoPins, DOMAIN_NOT_PINNED }, | 2634 {12, true, "\006crypto\003cat", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1470 {25, true, "\014bigshinylock\006minazo\003net", true, kNoPins, DOMAIN_NOT_PINN
ED }, | 2635 {25, true, "\014bigshinylock\006minazo\003net", true, kNoPins, DOMAIN_NOT_PINN
ED }, |
| 1471 {10, true, "\005crate\002io", true, kNoPins, DOMAIN_NOT_PINNED }, | 2636 {10, true, "\005crate\002io", true, kNoPins, DOMAIN_NOT_PINNED }, |
| 1472 {13, false, "\007twitter\003com", false, kTwitterComPins, DOMAIN_TWITTER_COM }
, | 2637 |
| 1473 {17, true, "\003www\007twitter\003com", false, kTwitterComPins, DOMAIN_TWITTER
_COM }, | 2638 {13, false, "\007twitter\003com", kTwitterHSTS, kTwitterComPins, DOMAIN_TWITTE
R_COM }, |
| 1474 {17, true, "\003api\007twitter\003com", false, kTwitterCDNPins, DOMAIN_TWITTER
_COM }, | 2639 {17, true, "\003www\007twitter\003com", kTwitterHSTS, kTwitterComPins, DOMAIN_
TWITTER_COM }, |
| 1475 {19, true, "\005oauth\007twitter\003com", false, kTwitterComPins, DOMAIN_TWITT
ER_COM }, | 2640 {17, true, "\003api\007twitter\003com", kTwitterHSTS, kTwitterCDNPins, DOMAIN_
TWITTER_COM }, |
| 1476 {20, true, "\006mobile\007twitter\003com", false, kTwitterComPins, DOMAIN_TWIT
TER_COM }, | 2641 {19, true, "\005oauth\007twitter\003com", kTwitterHSTS, kTwitterComPins, DOMAI
N_TWITTER_COM }, |
| 1477 {17, true, "\003dev\007twitter\003com", false, kTwitterComPins, DOMAIN_TWITTER
_COM }, | 2642 {20, true, "\006mobile\007twitter\003com", kTwitterHSTS, kTwitterComPins, DOMA
IN_TWITTER_COM }, |
| 1478 {22, true, "\010business\007twitter\003com", false, kTwitterComPins, DOMAIN_TW
ITTER_COM }, | 2643 {17, true, "\003dev\007twitter\003com", kTwitterHSTS, kTwitterComPins, DOMAIN_
TWITTER_COM }, |
| 2644 {22, true, "\010business\007twitter\003com", kTwitterHSTS, kTwitterComPins, DO
MAIN_TWITTER_COM }, |
| 1479 {22, true, "\010platform\007twitter\003com", false, kTwitterCDNPins, DOMAIN_TW
ITTER_COM }, | 2645 {22, true, "\010platform\007twitter\003com", false, kTwitterCDNPins, DOMAIN_TW
ITTER_COM }, |
| 1480 {15, true, "\003si0\005twimg\003com", false, kTwitterCDNPins, DOMAIN_TWIMG_COM
}, | 2646 {15, true, "\003si0\005twimg\003com", false, kTwitterCDNPins, DOMAIN_TWIMG_COM
}, |
| 1481 {23, true, "\010twimg0-a\010akamaihd\003net", false, kTwitterCDNPins, DOMAIN_A
KAMAIHD_NET }, | 2647 {23, true, "\010twimg0-a\010akamaihd\003net", false, kTwitterCDNPins, DOMAIN_A
KAMAIHD_NET }, |
| 1482 }; | 2648 }; |
| 1483 static const size_t kNumPreloadedSTS = ARRAYSIZE_UNSAFE(kPreloadedSTS); | 2649 static const size_t kNumPreloadedSTS = ARRAYSIZE_UNSAFE(kPreloadedSTS); |
| 1484 | 2650 |
| 1485 static const struct HSTSPreload kPreloadedSNISTS[] = { | 2651 static const struct HSTSPreload kPreloadedSNISTS[] = { |
| 2652 // These SNI-only domains must always use HTTPS. |
| 1486 {11, false, "\005gmail\003com", true, kGooglePins, DOMAIN_GMAIL_COM }, | 2653 {11, false, "\005gmail\003com", true, kGooglePins, DOMAIN_GMAIL_COM }, |
| 1487 {16, false, "\012googlemail\003com", true, kGooglePins, DOMAIN_GOOGLEMAIL_COM
}, | 2654 {16, false, "\012googlemail\003com", true, kGooglePins, DOMAIN_GOOGLEMAIL_COM
}, |
| 1488 {15, false, "\003www\005gmail\003com", true, kGooglePins, DOMAIN_GMAIL_COM }, | 2655 {15, false, "\003www\005gmail\003com", true, kGooglePins, DOMAIN_GMAIL_COM }, |
| 1489 {20, false, "\003www\012googlemail\003com", true, kGooglePins, DOMAIN_GOOGLEMA
IL_COM }, | 2656 {20, false, "\003www\012googlemail\003com", true, kGooglePins, DOMAIN_GOOGLEMA
IL_COM }, |
| 2657 // These SNI-only domains must use an acceptable certificate iff using |
| 2658 // HTTPS. |
| 1490 {22, true, "\020google-analytics\003com", false, kGooglePins, DOMAIN_GOOGLE_AN
ALYTICS_COM }, | 2659 {22, true, "\020google-analytics\003com", false, kGooglePins, DOMAIN_GOOGLE_AN
ALYTICS_COM }, |
| 2660 // www. requires SNI. |
| 1491 {18, true, "\014googlegroups\003com", false, kGooglePins, DOMAIN_GOOGLEGROUPS_
COM }, | 2661 {18, true, "\014googlegroups\003com", false, kGooglePins, DOMAIN_GOOGLEGROUPS_
COM }, |
| 1492 }; | 2662 }; |
| 1493 static const size_t kNumPreloadedSNISTS = ARRAYSIZE_UNSAFE(kPreloadedSNISTS); | 2663 static const size_t kNumPreloadedSNISTS = ARRAYSIZE_UNSAFE(kPreloadedSNISTS); |
| 1494 | 2664 |
| 1495 #endif // NET_BASE_TRANSPORT_SECURITY_STATE_STATIC_H_ | 2665 // Returns the HSTSPreload entry for the |canonicalized_host| in |entries|, |
| 2666 // or NULL if there is none. Prefers exact hostname matches to those that |
| 2667 // match only because HSTSPreload.include_subdomains is true. |
| 2668 // |
| 2669 // |canonicalized_host| should be the hostname as canonicalized by |
| 2670 // CanonicalizeHost. |
| 2671 static const struct HSTSPreload* GetHSTSPreload( |
| 2672 const std::string& canonicalized_host, |
| 2673 const struct HSTSPreload* entries, |
| 2674 size_t num_entries) { |
| 2675 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { |
| 2676 for (size_t j = 0; j < num_entries; j++) { |
| 2677 const struct HSTSPreload* entry = entries + j; |
| 2678 |
| 2679 if (i != 0 && !entry->include_subdomains) |
| 2680 continue; |
| 2681 |
| 2682 if (entry->length == canonicalized_host.size() - i && |
| 2683 memcmp(entry->dns_name, &canonicalized_host[i], entry->length) == 0) { |
| 2684 return entry; |
| 2685 } |
| 2686 } |
| 2687 } |
| 2688 |
| 2689 return NULL; |
| 2690 } |
| 2691 |
| 2692 // static |
| 2693 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host, |
| 2694 bool sni_available) { |
| 2695 std::string canonicalized_host = CanonicalizeHost(host); |
| 2696 const struct HSTSPreload* entry = |
| 2697 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS); |
| 2698 |
| 2699 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts) |
| 2700 return true; |
| 2701 |
| 2702 if (sni_available) { |
| 2703 entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS, |
| 2704 kNumPreloadedSNISTS); |
| 2705 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts) |
| 2706 return true; |
| 2707 } |
| 2708 |
| 2709 return false; |
| 2710 } |
| 2711 |
| 2712 // static |
| 2713 void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) { |
| 2714 std::string canonicalized_host = CanonicalizeHost(host); |
| 2715 |
| 2716 const struct HSTSPreload* entry = |
| 2717 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS); |
| 2718 |
| 2719 if (!entry) { |
| 2720 entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS, |
| 2721 kNumPreloadedSNISTS); |
| 2722 } |
| 2723 |
| 2724 DCHECK(entry); |
| 2725 DCHECK(entry->pins.required_hashes); |
| 2726 DCHECK(entry->second_level_domain_name != DOMAIN_NOT_PINNED); |
| 2727 |
| 2728 UMA_HISTOGRAM_ENUMERATION("Net.PublicKeyPinFailureDomain", |
| 2729 entry->second_level_domain_name, DOMAIN_NUM_EVENTS); |
| 2730 } |
| 2731 |
| 2732 // IsPreloadedSTS returns true if the canonicalized hostname should always be |
| 2733 // considered to have STS enabled. |
| 2734 bool TransportSecurityState::IsPreloadedSTS( |
| 2735 const std::string& canonicalized_host, |
| 2736 bool sni_available, |
| 2737 DomainState* out) { |
| 2738 DCHECK(CalledOnValidThread()); |
| 2739 |
| 2740 out->preloaded = true; |
| 2741 out->mode = DomainState::MODE_STRICT; |
| 2742 out->include_subdomains = false; |
| 2743 |
| 2744 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { |
| 2745 std::string host_sub_chunk(&canonicalized_host[i], |
| 2746 canonicalized_host.size() - i); |
| 2747 out->domain = DNSDomainToString(host_sub_chunk); |
| 2748 std::string hashed_host(HashHost(host_sub_chunk)); |
| 2749 if (forced_hosts_.find(hashed_host) != forced_hosts_.end()) { |
| 2750 *out = forced_hosts_[hashed_host]; |
| 2751 out->domain = DNSDomainToString(host_sub_chunk); |
| 2752 out->preloaded = true; |
| 2753 return true; |
| 2754 } |
| 2755 bool ret; |
| 2756 if (HasPreload(kPreloadedSTS, kNumPreloadedSTS, canonicalized_host, i, out, |
| 2757 &ret)) { |
| 2758 return ret; |
| 2759 } |
| 2760 if (sni_available && |
| 2761 HasPreload(kPreloadedSNISTS, kNumPreloadedSNISTS, canonicalized_host, i, |
| 2762 out, &ret)) { |
| 2763 return ret; |
| 2764 } |
| 2765 } |
| 2766 |
| 2767 return false; |
| 2768 } |
| 2769 |
| 2770 static std::string HashesToBase64String( |
| 2771 const FingerprintVector& hashes) { |
| 2772 std::vector<std::string> hashes_strs; |
| 2773 for (FingerprintVector::const_iterator |
| 2774 i = hashes.begin(); i != hashes.end(); i++) { |
| 2775 std::string s; |
| 2776 const std::string hash_str(reinterpret_cast<const char*>(i->data), |
| 2777 sizeof(i->data)); |
| 2778 base::Base64Encode(hash_str, &s); |
| 2779 hashes_strs.push_back(s); |
| 2780 } |
| 2781 |
| 2782 return JoinString(hashes_strs, ','); |
| 2783 } |
| 2784 |
| 2785 TransportSecurityState::DomainState::DomainState() |
| 2786 : mode(MODE_STRICT), |
| 2787 created(base::Time::Now()), |
| 2788 include_subdomains(false), |
| 2789 preloaded(false) { |
| 2790 } |
| 2791 |
| 2792 TransportSecurityState::DomainState::~DomainState() { |
| 2793 } |
| 2794 |
| 2795 bool TransportSecurityState::DomainState::IsChainOfPublicKeysPermitted( |
| 2796 const FingerprintVector& hashes) { |
| 2797 |
| 2798 if (HashesIntersect(bad_preloaded_spki_hashes, hashes)) { |
| 2799 LOG(ERROR) << "Rejecting public key chain for domain " << domain |
| 2800 << ". Validated chain: " << HashesToBase64String(hashes) |
| 2801 << ", matches one or more bad hashes: " |
| 2802 << HashesToBase64String(bad_preloaded_spki_hashes); |
| 2803 return false; |
| 2804 } |
| 2805 |
| 2806 if (!(dynamic_spki_hashes.empty() && preloaded_spki_hashes.empty()) && |
| 2807 !HashesIntersect(dynamic_spki_hashes, hashes) && |
| 2808 !HashesIntersect(preloaded_spki_hashes, hashes)) { |
| 2809 LOG(ERROR) << "Rejecting public key chain for domain " << domain |
| 2810 << ". Validated chain: " << HashesToBase64String(hashes) |
| 2811 << ", expected: " << HashesToBase64String(dynamic_spki_hashes) |
| 2812 << " or: " << HashesToBase64String(preloaded_spki_hashes); |
| 2813 |
| 2814 return false; |
| 2815 } |
| 2816 |
| 2817 return true; |
| 2818 } |
| 2819 |
| 2820 bool TransportSecurityState::DomainState::IsMoreStrict( |
| 2821 const TransportSecurityState::DomainState& other) { |
| 2822 if (this->dynamic_spki_hashes.empty() && !other.dynamic_spki_hashes.empty()) |
| 2823 return false; |
| 2824 |
| 2825 if (!this->include_subdomains && other.include_subdomains) |
| 2826 return false; |
| 2827 |
| 2828 return true; |
| 2829 } |
| 2830 |
| 2831 bool TransportSecurityState::DomainState::ShouldRedirectHTTPToHTTPS() |
| 2832 const { |
| 2833 return mode == MODE_STRICT; |
| 2834 } |
| 2835 |
| 2836 } // namespace |
| OLD | NEW |