OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // This file is automatically generated by hsts_preloaded_generate.go |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | 2 |
5 #ifndef NET_BASE_PUBLIC_KEY_HASHES_ | 3 #ifndef NET_BASE_HSTS_PRELOADED_H_ |
6 #define NET_BASE_PUBLIC_KEY_HASHES_ | 4 #define NET_BASE_HSTS_PRELOADED_H_ |
7 #pragma once | 5 #pragma once |
8 | 6 |
9 // This file contains SubjectPublicKeyInfo hashes for public key pinning. The | 7 // These are SubjectPublicKeyInfo hashes for public key pinning. The |
10 // hashes are base64 encoded, SHA1 digests. | 8 // hashes are base64 encoded, SHA1 digests. |
11 | 9 |
10 static const char kSPKIHash_TestSPKI[] = | |
11 "sha1/AAAAAAAAAAAAAAAAAAAAAAAAAAA="; | |
12 | |
12 #if 0 | 13 #if 0 |
13 -----BEGIN CERTIFICATE----- | 14 -----BEGIN CERTIFICATE----- |
palmer
2012/03/26 23:40:21
Since the certificates are in the .certs file, may
agl
2012/03/28 16:20:30
That's a fair point. Although I'd like to remove t
| |
14 MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG | 15 MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG |
15 A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz | 16 A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz |
16 cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 | 17 cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 |
17 MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV | 18 MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV |
18 BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt | 19 BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt |
19 YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN | 20 YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN |
20 ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE | 21 ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE |
21 BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is | 22 BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is |
22 I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G | 23 I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G |
23 CSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i | 24 CSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
72 Af8CAQAwOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20v | 73 Af8CAQAwOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20v |
73 Y3Jscy9zZWN1cmVjYS5jcmwwDQYJKoZIhvcNAQEFBQADgYEAuIojxkiWsRF8YHde | 74 Y3Jscy9zZWN1cmVjYS5jcmwwDQYJKoZIhvcNAQEFBQADgYEAuIojxkiWsRF8YHde |
74 BZqrocb6ghwYB8TrgbCoZutJqOkM0ymt9e8kTP3kS8p/XmOrmSfLnzYhLLkQYGfN | 75 BZqrocb6ghwYB8TrgbCoZutJqOkM0ymt9e8kTP3kS8p/XmOrmSfLnzYhLLkQYGfN |
75 0rTw8Ktx5YtaiScRhKqOv5nwnQkhClIZmloJ0pC3+gz4fniisIWvXEyZ2VxVKfml | 76 0rTw8Ktx5YtaiScRhKqOv5nwnQkhClIZmloJ0pC3+gz4fniisIWvXEyZ2VxVKfml |
76 UUIuOss4jHg7y/j7lYe8vJD5UDI= | 77 UUIuOss4jHg7y/j7lYe8vJD5UDI= |
77 -----END CERTIFICATE----- | 78 -----END CERTIFICATE----- |
78 #endif | 79 #endif |
79 static const char kSPKIHash_Google1024[] = | 80 static const char kSPKIHash_Google1024[] = |
80 "sha1/QMVAHW+MuvCLAO3vse6H0AWzuc0="; | 81 "sha1/QMVAHW+MuvCLAO3vse6H0AWzuc0="; |
81 | 82 |
82 // Not yet used publicly. | |
83 static const char kSPKIHash_Google2048[] = | 83 static const char kSPKIHash_Google2048[] = |
84 "sha1/AbkhxY0L343gKf+cki7NVWp+ozk="; | 84 "sha1/AbkhxY0L343gKf+cki7NVWp+ozk="; |
85 | 85 |
86 #if 0 | 86 #if 0 |
87 -----BEGIN CERTIFICATE----- | 87 -----BEGIN CERTIFICATE----- |
88 MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV | 88 MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV |
89 UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy | 89 UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy |
90 dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 | 90 dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 |
91 MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx | 91 MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx |
92 dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B | 92 dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
316 eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF | 316 eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF |
317 hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 | 317 hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 |
318 Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe | 318 Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe |
319 vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep | 319 vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep |
320 +OkuE6N36B9K | 320 +OkuE6N36B9K |
321 -----END CERTIFICATE----- | 321 -----END CERTIFICATE----- |
322 #endif | 322 #endif |
323 static const char kSPKIHash_DigiCertEVRoot[] = | 323 static const char kSPKIHash_DigiCertEVRoot[] = |
324 "sha1/gzF+YoVCU9bXeDGQ7JGQVumRueM="; | 324 "sha1/gzF+YoVCU9bXeDGQ7JGQVumRueM="; |
325 | 325 |
326 // Not public | |
327 static const char kSPKIHash_Tor1[] = | 326 static const char kSPKIHash_Tor1[] = |
328 "sha1/juNxSTv9UANmpC9kF5GKpmWNx3Y="; | 327 "sha1/juNxSTv9UANmpC9kF5GKpmWNx3Y="; |
328 | |
329 static const char kSPKIHash_Tor2[] = | 329 static const char kSPKIHash_Tor2[] = |
330 "sha1/lia43lPolzSPVIq34Dw57uYcLD8="; | 330 "sha1/lia43lPolzSPVIq34Dw57uYcLD8="; |
331 | |
331 static const char kSPKIHash_Tor3[] = | 332 static const char kSPKIHash_Tor3[] = |
332 "sha1/rzEyQIKOh77j87n5bjWUNguXF8Y="; | 333 "sha1/rzEyQIKOh77j87n5bjWUNguXF8Y="; |
333 | 334 |
334 #if 0 | 335 #if 0 |
335 -----BEGIN CERTIFICATE----- | 336 -----BEGIN CERTIFICATE----- |
336 MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ | 337 MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ |
337 BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh | 338 BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh |
338 c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05 | 339 c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05 |
339 NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD | 340 NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD |
340 VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp | 341 VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp |
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
571 seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz | 572 seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz |
572 4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ | 573 4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ |
573 BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR | 574 BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR |
574 lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 | 575 lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 |
575 7M2CYfE45k+XmCpajQ== | 576 7M2CYfE45k+XmCpajQ== |
576 -----END CERTIFICATE----- | 577 -----END CERTIFICATE----- |
577 #endif | 578 #endif |
578 static const char kSPKIHash_VeriSignUniversal[] = | 579 static const char kSPKIHash_VeriSignUniversal[] = |
579 "sha1/u8I+KQuzKHcdrT6iTb30I70GsD0="; | 580 "sha1/u8I+KQuzKHcdrT6iTb30I70GsD0="; |
580 | 581 |
581 // Not public | |
582 static const char kSPKIHash_Twitter1[] = | 582 static const char kSPKIHash_Twitter1[] = |
583 "sha1/Vv7zwhR9TtOIN/29MFI4cgHld40="; | 583 "sha1/Vv7zwhR9TtOIN/29MFI4cgHld40="; |
584 | 584 |
585 #if 0 | 585 #if 0 |
586 -----BEGIN CERTIFICATE----- | 586 -----BEGIN CERTIFICATE----- |
587 MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW | 587 MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW |
588 MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs | 588 MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs |
589 IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG | 589 IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG |
590 EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg | 590 EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg |
591 R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A | 591 R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
726 AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH | 726 AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH |
727 SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G | 727 SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G |
728 spki4cErx5z481+oghLrGREt | 728 spki4cErx5z481+oghLrGREt |
729 -----END CERTIFICATE----- | 729 -----END CERTIFICATE----- |
730 #endif | 730 #endif |
731 static const char kSPKIHash_GeoTrustPrimary_G3[] = | 731 static const char kSPKIHash_GeoTrustPrimary_G3[] = |
732 "sha1/nKmNAK90Dd2BgNITRaWLjy6UONY="; | 732 "sha1/nKmNAK90Dd2BgNITRaWLjy6UONY="; |
733 | 733 |
734 #if 0 | 734 #if 0 |
735 -----BEGIN CERTIFICATE----- | 735 -----BEGIN CERTIFICATE----- |
736 MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u | 736 MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML |
agl
2012/03/26 21:20:29
Note that this is the same certificate, but the PE
| |
737 ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp | 737 RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp |
738 bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV | 738 bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 |
739 BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx | 739 IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp |
740 NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 | 740 ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 |
741 d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl | 741 MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 |
742 MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u | 742 LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp |
743 ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A | 743 YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG |
744 MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL | 744 A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp |
745 Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr | 745 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq |
746 hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW | 746 K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe |
747 nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi | 747 sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX |
748 VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E | 748 MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT |
749 BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ | 749 XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ |
750 KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy | 750 HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH |
751 T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf | 751 4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV |
752 zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT | 752 HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub |
753 J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e | 753 j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo |
754 nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE= | 754 U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf |
755 zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b | |
756 u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ | |
757 bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er | |
758 fF6adulZkMV8gzURZVE= | |
755 -----END CERTIFICATE----- | 759 -----END CERTIFICATE----- |
756 #endif | 760 #endif |
757 static const char kSPKIHash_Entrust_2048[] = | 761 static const char kSPKIHash_Entrust_2048[] = |
758 "sha1/VeSB0RGAvtiJuQijMfmhJAkWuXA="; | 762 "sha1/VeSB0RGAvtiJuQijMfmhJAkWuXA="; |
759 | 763 |
760 #if 0 | 764 #if 0 |
761 -----BEGIN CERTIFICATE----- | 765 -----BEGIN CERTIFICATE----- |
762 MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC | 766 MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC |
763 VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 | 767 VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 |
764 Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW | 768 Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW |
(...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1228 r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4 | 1232 r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4 |
1229 04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r | 1233 04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r |
1230 GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9 | 1234 GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9 |
1231 3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P | 1235 3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P |
1232 lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ | 1236 lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ |
1233 -----END CERTIFICATE----- | 1237 -----END CERTIFICATE----- |
1234 #endif | 1238 #endif |
1235 static const char kSPKIHash_GTECyberTrustGlobalRoot[] = | 1239 static const char kSPKIHash_GTECyberTrustGlobalRoot[] = |
1236 "sha1/WXkS3mF11m/EI7d3E3THlt5viHI="; | 1240 "sha1/WXkS3mF11m/EI7d3E3THlt5viHI="; |
1237 | 1241 |
1238 #endif // NET_BASE_PUBLIC_KEY_HASHES_ | 1242 // The following is static data describing the hosts that are hardcoded with |
1239 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1243 // certificate pins or HSTS information. |
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 } | |
2388 | 1244 |
2389 // kNoRejectedPublicKeys is a placeholder for when no public keys are rejected. | 1245 // kNoRejectedPublicKeys is a placeholder for when no public keys are rejected. |
2390 static const char* const kNoRejectedPublicKeys[] = { | 1246 static const char* const kNoRejectedPublicKeys[] = { |
2391 NULL, | 1247 NULL, |
2392 }; | 1248 }; |
2393 | 1249 |
1250 static const char* const kTestAcceptableCerts[] = { | |
1251 kSPKIHash_TestSPKI, | |
1252 NULL, | |
1253 }; | |
1254 #define kTestPins { \ | |
1255 kTestAcceptableCerts, \ | |
1256 kNoRejectedPublicKeys, \ | |
1257 } | |
1258 | |
2394 static const char* const kGoogleAcceptableCerts[] = { | 1259 static const char* const kGoogleAcceptableCerts[] = { |
2395 kSPKIHash_VeriSignClass3, | 1260 kSPKIHash_VeriSignClass3, |
2396 kSPKIHash_VeriSignClass3_G3, | 1261 kSPKIHash_VeriSignClass3_G3, |
2397 kSPKIHash_Google1024, | 1262 kSPKIHash_Google1024, |
2398 kSPKIHash_Google2048, | 1263 kSPKIHash_Google2048, |
2399 kSPKIHash_EquifaxSecureCA, | 1264 kSPKIHash_EquifaxSecureCA, |
2400 NULL, | 1265 NULL, |
2401 }; | 1266 }; |
2402 static const char* const kGoogleRejectedCerts[] = { | 1267 static const char* const kGoogleRejectedCerts[] = { |
2403 kSPKIHash_Aetna, | 1268 kSPKIHash_Aetna, |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2444 kSPKIHash_GeoTrustPrimary_G2, | 1309 kSPKIHash_GeoTrustPrimary_G2, |
2445 kSPKIHash_GeoTrustPrimary_G3, | 1310 kSPKIHash_GeoTrustPrimary_G3, |
2446 kSPKIHash_Twitter1, | 1311 kSPKIHash_Twitter1, |
2447 NULL, | 1312 NULL, |
2448 }; | 1313 }; |
2449 #define kTwitterComPins { \ | 1314 #define kTwitterComPins { \ |
2450 kTwitterComAcceptableCerts, \ | 1315 kTwitterComAcceptableCerts, \ |
2451 kNoRejectedPublicKeys, \ | 1316 kNoRejectedPublicKeys, \ |
2452 } | 1317 } |
2453 | 1318 |
2454 // kTwitterCDNAcceptableCerts are the set of public keys valid for Twitter's | |
2455 // CDNs, which includes all the keys from kTwitterComAcceptableCerts. | |
2456 static const char* const kTwitterCDNAcceptableCerts[] = { | 1319 static const char* const kTwitterCDNAcceptableCerts[] = { |
2457 kSPKIHash_VeriSignClass1, | 1320 kSPKIHash_VeriSignClass1, |
2458 kSPKIHash_VeriSignClass3, | 1321 kSPKIHash_VeriSignClass3, |
2459 kSPKIHash_VeriSignClass3_G4, | 1322 kSPKIHash_VeriSignClass3_G4, |
2460 kSPKIHash_VeriSignClass4_G3, | 1323 kSPKIHash_VeriSignClass4_G3, |
2461 kSPKIHash_VeriSignClass3_G3, | 1324 kSPKIHash_VeriSignClass3_G3, |
2462 kSPKIHash_VeriSignClass1_G3, | 1325 kSPKIHash_VeriSignClass1_G3, |
2463 kSPKIHash_VeriSignClass2_G3, | 1326 kSPKIHash_VeriSignClass2_G3, |
2464 kSPKIHash_VeriSignClass3_G2, | 1327 kSPKIHash_VeriSignClass3_G2, |
2465 kSPKIHash_VeriSignClass2_G2, | 1328 kSPKIHash_VeriSignClass2_G2, |
2466 kSPKIHash_VeriSignClass3_G5, | 1329 kSPKIHash_VeriSignClass3_G5, |
2467 kSPKIHash_VeriSignUniversal, | 1330 kSPKIHash_VeriSignUniversal, |
2468 kSPKIHash_GeoTrustGlobal, | 1331 kSPKIHash_GeoTrustGlobal, |
2469 kSPKIHash_GeoTrustGlobal2, | 1332 kSPKIHash_GeoTrustGlobal2, |
2470 kSPKIHash_GeoTrustUniversal, | 1333 kSPKIHash_GeoTrustUniversal, |
2471 kSPKIHash_GeoTrustUniversal2, | 1334 kSPKIHash_GeoTrustUniversal2, |
2472 kSPKIHash_GeoTrustPrimary, | 1335 kSPKIHash_GeoTrustPrimary, |
2473 kSPKIHash_GeoTrustPrimary_G2, | 1336 kSPKIHash_GeoTrustPrimary_G2, |
2474 kSPKIHash_GeoTrustPrimary_G3, | 1337 kSPKIHash_GeoTrustPrimary_G3, |
2475 kSPKIHash_Twitter1, | 1338 kSPKIHash_Twitter1, |
2476 | |
2477 kSPKIHash_Entrust_2048, | 1339 kSPKIHash_Entrust_2048, |
2478 kSPKIHash_Entrust_EV, | 1340 kSPKIHash_Entrust_EV, |
2479 kSPKIHash_Entrust_G2, | 1341 kSPKIHash_Entrust_G2, |
2480 kSPKIHash_Entrust_SSL, | 1342 kSPKIHash_Entrust_SSL, |
2481 kSPKIHash_AAACertificateServices, | 1343 kSPKIHash_AAACertificateServices, |
2482 kSPKIHash_AddTrustClass1CARoot, | 1344 kSPKIHash_AddTrustClass1CARoot, |
2483 kSPKIHash_AddTrustExternalCARoot, | 1345 kSPKIHash_AddTrustExternalCARoot, |
2484 kSPKIHash_AddTrustPublicCARoot, | 1346 kSPKIHash_AddTrustPublicCARoot, |
2485 kSPKIHash_AddTrustQualifiedCARoot, | 1347 kSPKIHash_AddTrustQualifiedCARoot, |
2486 kSPKIHash_COMODOCertificationAuthority, | 1348 kSPKIHash_COMODOCertificationAuthority, |
2487 kSPKIHash_SecureCertificateServices, | 1349 kSPKIHash_SecureCertificateServices, |
2488 kSPKIHash_TrustedCertificateServices, | 1350 kSPKIHash_TrustedCertificateServices, |
2489 kSPKIHash_UTNDATACorpSGC, | 1351 kSPKIHash_UTNDATACorpSGC, |
2490 kSPKIHash_UTNUSERFirstClientAuthenticationandEmail, | 1352 kSPKIHash_UTNUSERFirstClientAuthenticationandEmail, |
2491 kSPKIHash_UTNUSERFirstHardware, | 1353 kSPKIHash_UTNUSERFirstHardware, |
2492 kSPKIHash_UTNUSERFirstObject, | 1354 kSPKIHash_UTNUSERFirstObject, |
2493 kSPKIHash_GTECyberTrustGlobalRoot, | 1355 kSPKIHash_GTECyberTrustGlobalRoot, |
2494 NULL, | 1356 NULL, |
2495 }; | 1357 }; |
2496 #define kTwitterCDNPins { \ | 1358 #define kTwitterCDNPins { \ |
2497 kTwitterCDNAcceptableCerts, \ | 1359 kTwitterCDNAcceptableCerts, \ |
2498 kNoRejectedPublicKeys, \ | 1360 kNoRejectedPublicKeys, \ |
2499 } | 1361 } |
2500 | 1362 |
2501 // kTestAcceptableCerts doesn't actually match any public keys and is used | 1363 #define kNoPins {\ |
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 { \ | |
2513 NULL, NULL, \ | 1364 NULL, NULL, \ |
2514 } | 1365 } |
2515 | 1366 |
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. | |
2524 static const struct HSTSPreload kPreloadedSTS[] = { | 1367 static const struct HSTSPreload kPreloadedSTS[] = { |
2525 // (*.)google.com, iff using SSL must use an acceptable certificate. | 1368 {25, true, "\013pinningtest\007appspot\003com", false, kTestPins, DOMAIN_APPSP OT_COM }, |
2526 {12, true, "\006google\003com", false, kGooglePins, DOMAIN_GOOGLE_COM }, | 1369 {12, true, "\006google\003com", false, kGooglePins, DOMAIN_GOOGLE_COM }, |
2527 {25, true, "\013pinningtest\007appspot\003com", false, kTestPins, DOMAIN_APPSP OT_COM }, | 1370 {19, true, "\006health\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM }, |
2528 // Now we force HTTPS for subtrees of google.com. | |
2529 {19, true, "\006health\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM }, | |
2530 {21, true, "\010checkout\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_C OM }, | 1371 {21, true, "\010checkout\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_C OM }, |
2531 {19, true, "\006chrome\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM }, | 1372 {19, true, "\006chrome\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM }, |
2532 {17, true, "\004docs\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM } , | 1373 {17, true, "\004docs\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM } , |
2533 {18, true, "\005sites\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM }, | 1374 {18, true, "\005sites\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM }, |
2534 {25, true, "\014spreadsheets\006google\003com", true, kGooglePins, DOMAIN_GOOG LE_COM }, | 1375 {25, true, "\014spreadsheets\006google\003com", true, kGooglePins, DOMAIN_GOOG LE_COM }, |
2535 {22, false, "\011appengine\006google\003com", true, kGooglePins, DOMAIN_GOOGLE _COM }, | 1376 {22, false, "\011appengine\006google\003com", true, kGooglePins, DOMAIN_GOOGLE _COM }, |
2536 {22, true, "\011encrypted\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_ COM }, | 1377 {22, true, "\011encrypted\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_ COM }, |
2537 {21, true, "\010accounts\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_C OM }, | 1378 {21, true, "\010accounts\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_C OM }, |
2538 {21, true, "\010profiles\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_C OM }, | 1379 {21, true, "\010profiles\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_C OM }, |
2539 {17, true, "\004mail\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM } , | 1380 {17, true, "\004mail\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM } , |
2540 {23, true, "\012talkgadget\006google\003com", true, kGooglePins, DOMAIN_GOOGLE _COM }, | 1381 {23, true, "\012talkgadget\006google\003com", true, kGooglePins, DOMAIN_GOOGLE _COM }, |
2541 {17, true, "\004talk\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM } , | 1382 {17, true, "\004talk\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM } , |
2542 {29, true, "\020hostedtalkgadget\006google\003com", true, kGooglePins, DOMAIN_ GOOGLE_COM }, | 1383 {29, true, "\020hostedtalkgadget\006google\003com", true, kGooglePins, DOMAIN_ GOOGLE_COM }, |
2543 {17, true, "\004plus\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM } , | 1384 {17, true, "\004plus\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM } , |
2544 // Other Google-related domains that must use HTTPS. | |
2545 {20, true, "\006market\007android\003com", true, kGooglePins, DOMAIN_ANDROID_C OM }, | 1385 {20, true, "\006market\007android\003com", true, kGooglePins, DOMAIN_ANDROID_C OM }, |
2546 {26, true, "\003ssl\020google-analytics\003com", true, kGooglePins, DOMAIN_GOO GLE_ANALYTICS_COM }, | 1386 {26, true, "\003ssl\020google-analytics\003com", true, kGooglePins, DOMAIN_GOO GLE_ANALYTICS_COM }, |
2547 {18, true, "\005drive\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM }, | 1387 {18, true, "\005drive\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM }, |
2548 {16, true, "\012googleplex\003com", true, kGooglePins, DOMAIN_GOOGLEPLEX_COM } , | 1388 {16, true, "\012googleplex\003com", true, kGooglePins, DOMAIN_GOOGLEPLEX_COM } , |
2549 {19, true, "\006groups\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM }, | 1389 {19, true, "\006groups\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM }, |
2550 {17, true, "\004apis\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM } , | 1390 {17, true, "\004apis\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM } , |
2551 // chart.apis.google.com is *not* HSTS because the certificate doesn't match | 1391 {23, true, "\005chart\004apis\006google\003com", false, kGooglePins, DOMAIN_GO OGLE_COM }, |
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. | |
2558 {11, true, "\005ytimg\003com", false, kGooglePins, DOMAIN_YTIMG_COM }, | 1392 {11, true, "\005ytimg\003com", false, kGooglePins, DOMAIN_YTIMG_COM }, |
2559 {23, true, "\021googleusercontent\003com", false, kGooglePins, DOMAIN_GOOGLEUS ERCONTENT_COM }, | 1393 {23, true, "\021googleusercontent\003com", false, kGooglePins, DOMAIN_GOOGLEUS ERCONTENT_COM }, |
2560 {13, true, "\007youtube\003com", false, kGooglePins, DOMAIN_YOUTUBE_COM }, | 1394 {13, true, "\007youtube\003com", false, kGooglePins, DOMAIN_YOUTUBE_COM }, |
2561 {16, true, "\012googleapis\003com", false, kGooglePins, DOMAIN_GOOGLEAPIS_COM }, | 1395 {16, true, "\012googleapis\003com", false, kGooglePins, DOMAIN_GOOGLEAPIS_COM }, |
2562 {22, true, "\020googleadservices\003com", false, kGooglePins, DOMAIN_GOOGLEADS ERVICES_COM }, | 1396 {22, true, "\020googleadservices\003com", false, kGooglePins, DOMAIN_GOOGLEADS ERVICES_COM }, |
2563 {16, true, "\012googlecode\003com", false, kGooglePins, DOMAIN_GOOGLECODE_COM }, | 1397 {16, true, "\012googlecode\003com", false, kGooglePins, DOMAIN_GOOGLECODE_COM }, |
2564 {13, true, "\007appspot\003com", false, kGooglePins, DOMAIN_APPSPOT_COM }, | 1398 {13, true, "\007appspot\003com", false, kGooglePins, DOMAIN_APPSPOT_COM }, |
2565 {23, true, "\021googlesyndication\003com", false, kGooglePins, DOMAIN_GOOGLESY NDICATION_COM }, | 1399 {23, true, "\021googlesyndication\003com", false, kGooglePins, DOMAIN_GOOGLESY NDICATION_COM }, |
2566 {17, true, "\013doubleclick\003net", false, kGooglePins, DOMAIN_DOUBLECLICK_NE T }, | 1400 {17, true, "\013doubleclick\003net", false, kGooglePins, DOMAIN_DOUBLECLICK_NE T }, |
2567 {17, true, "\003ssl\007gstatic\003com", false, kGooglePins, DOMAIN_GSTATIC_COM }, | 1401 {17, true, "\003ssl\007gstatic\003com", false, kGooglePins, DOMAIN_GSTATIC_COM }, |
2568 // Exclude the learn.doubleclick.net subdomain because it uses a different | |
2569 // CA. | |
2570 {23, true, "\005learn\013doubleclick\003net", false, kNoPins, DOMAIN_NOT_PINNE D }, | 1402 {23, true, "\005learn\013doubleclick\003net", false, kNoPins, DOMAIN_NOT_PINNE D }, |
2571 // Now we force HTTPS for other sites that have requested it. | |
2572 {16, false, "\003www\006paypal\003com", true, kNoPins, DOMAIN_NOT_PINNED }, | 1403 {16, false, "\003www\006paypal\003com", true, kNoPins, DOMAIN_NOT_PINNED }, |
2573 {16, false, "\003www\006elanex\003biz", true, kNoPins, DOMAIN_NOT_PINNED }, | 1404 {16, false, "\003www\006elanex\003biz", true, kNoPins, DOMAIN_NOT_PINNED }, |
2574 {12, true, "\006jottit\003com", true, kNoPins, DOMAIN_NOT_PINNED }, | 1405 {12, true, "\006jottit\003com", true, kNoPins, DOMAIN_NOT_PINNED }, |
2575 {19, true, "\015sunshinepress\003org", true, kNoPins, DOMAIN_NOT_PINNED }, | 1406 {19, true, "\015sunshinepress\003org", true, kNoPins, DOMAIN_NOT_PINNED }, |
2576 {21, false, "\003www\013noisebridge\003net", true, kNoPins, DOMAIN_NOT_PINNED }, | 1407 {21, false, "\003www\013noisebridge\003net", true, kNoPins, DOMAIN_NOT_PINNED }, |
2577 {10, false, "\004neg9\003org", true, kNoPins, DOMAIN_NOT_PINNED }, | 1408 {10, false, "\004neg9\003org", true, kNoPins, DOMAIN_NOT_PINNED }, |
2578 {12, true, "\006riseup\003net", true, kNoPins, DOMAIN_NOT_PINNED }, | 1409 {12, true, "\006riseup\003net", true, kNoPins, DOMAIN_NOT_PINNED }, |
2579 {11, false, "\006factor\002cc", true, kNoPins, DOMAIN_NOT_PINNED }, | 1410 {11, false, "\006factor\002cc", true, kNoPins, DOMAIN_NOT_PINNED }, |
2580 {22, false, "\007members\010mayfirst\003org", true, kNoPins, DOMAIN_NOT_PINNED }, | 1411 {22, false, "\007members\010mayfirst\003org", true, kNoPins, DOMAIN_NOT_PINNED }, |
2581 {22, false, "\007support\010mayfirst\003org", true, kNoPins, DOMAIN_NOT_PINNED }, | 1412 {22, false, "\007support\010mayfirst\003org", true, kNoPins, DOMAIN_NOT_PINNED }, |
2582 {17, false, "\002id\010mayfirst\003org", true, kNoPins, DOMAIN_NOT_PINNED }, | 1413 {17, false, "\002id\010mayfirst\003org", true, kNoPins, DOMAIN_NOT_PINNED }, |
2583 {20, false, "\005lists\010mayfirst\003org", true, kNoPins, DOMAIN_NOT_PINNED } , | 1414 {20, false, "\005lists\010mayfirst\003org", true, kNoPins, DOMAIN_NOT_PINNED } , |
2584 {19, true, "\015splendidbacon\003com", true, kNoPins, DOMAIN_NOT_PINNED }, | 1415 {19, true, "\015splendidbacon\003com", true, kNoPins, DOMAIN_NOT_PINNED }, |
2585 {28, false, "\016aladdinschools\007appspot\003com", true, kNoPins, DOMAIN_NOT_ PINNED }, | 1416 {28, false, "\016aladdinschools\007appspot\003com", true, kNoPins, DOMAIN_NOT_ PINNED }, |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2618 {10, false, "\004kyps\003net", true, kNoPins, DOMAIN_NOT_PINNED }, | 1449 {10, false, "\004kyps\003net", true, kNoPins, DOMAIN_NOT_PINNED }, |
2619 {14, false, "\003www\004kyps\003net", true, kNoPins, DOMAIN_NOT_PINNED }, | 1450 {14, false, "\003www\004kyps\003net", true, kNoPins, DOMAIN_NOT_PINNED }, |
2620 {17, true, "\003app\007recurly\003com", true, kNoPins, DOMAIN_NOT_PINNED }, | 1451 {17, true, "\003app\007recurly\003com", true, kNoPins, DOMAIN_NOT_PINNED }, |
2621 {17, true, "\003api\007recurly\003com", true, kNoPins, DOMAIN_NOT_PINNED }, | 1452 {17, true, "\003api\007recurly\003com", true, kNoPins, DOMAIN_NOT_PINNED }, |
2622 {13, false, "\007greplin\003com", true, kNoPins, DOMAIN_NOT_PINNED }, | 1453 {13, false, "\007greplin\003com", true, kNoPins, DOMAIN_NOT_PINNED }, |
2623 {17, false, "\003www\007greplin\003com", true, kNoPins, DOMAIN_NOT_PINNED }, | 1454 {17, false, "\003www\007greplin\003com", true, kNoPins, DOMAIN_NOT_PINNED }, |
2624 {27, true, "\006luneta\016nearbuysystems\003com", true, kNoPins, DOMAIN_NOT_PI NNED }, | 1455 {27, true, "\006luneta\016nearbuysystems\003com", true, kNoPins, DOMAIN_NOT_PI NNED }, |
2625 {12, true, "\006ubertt\003org", true, kNoPins, DOMAIN_NOT_PINNED }, | 1456 {12, true, "\006ubertt\003org", true, kNoPins, DOMAIN_NOT_PINNED }, |
2626 {9, true, "\004pixi\002me", true, kNoPins, DOMAIN_NOT_PINNED }, | 1457 {9, true, "\004pixi\002me", true, kNoPins, DOMAIN_NOT_PINNED }, |
2627 {14, true, "\010grepular\003com", true, kNoPins, DOMAIN_NOT_PINNED }, | 1458 {14, true, "\010grepular\003com", true, kNoPins, DOMAIN_NOT_PINNED }, |
2628 {16, false , "\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED }, | 1459 {16, false, "\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED }, |
2629 {20, false , "\003www\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED }, | 1460 {20, false, "\003www\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED } , |
2630 {26, false , "\011developer\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_P INNED }, | 1461 {26, false, "\011developer\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PI NNED }, |
2631 {30, false , "\003www\011developer\012mydigipass\003com", true, kNoPins, DOMAI N_NOT_PINNED }, | 1462 {30, false, "\003www\011developer\012mydigipass\003com", true, kNoPins, DOMAIN _NOT_PINNED }, |
2632 {24, false , "\007sandbox\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PIN NED }, | 1463 {24, false, "\007sandbox\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINN ED }, |
2633 {28, false , "\003www\007sandbox\012mydigipass\003com", true, kNoPins, DOMAIN_ NOT_PINNED }, | 1464 {28, false, "\003www\007sandbox\012mydigipass\003com", true, kNoPins, DOMAIN_N OT_PINNED }, |
2634 {12, true, "\006crypto\003cat", true, kNoPins, DOMAIN_NOT_PINNED }, | 1465 {12, true, "\006crypto\003cat", true, kNoPins, DOMAIN_NOT_PINNED }, |
2635 {25, true, "\014bigshinylock\006minazo\003net", true, kNoPins, DOMAIN_NOT_PINN ED }, | 1466 {25, true, "\014bigshinylock\006minazo\003net", true, kNoPins, DOMAIN_NOT_PINN ED }, |
2636 {10, true, "\005crate\002io", true, kNoPins, DOMAIN_NOT_PINNED }, | 1467 {10, true, "\005crate\002io", true, kNoPins, DOMAIN_NOT_PINNED }, |
2637 | 1468 {13, false, "\007twitter\003com", false, kTwitterComPins, DOMAIN_TWITTER_COM } , |
2638 {13, false, "\007twitter\003com", kTwitterHSTS, kTwitterComPins, DOMAIN_TWITTE R_COM }, | 1469 {17, true, "\003www\007twitter\003com", false, kTwitterComPins, DOMAIN_TWITTER _COM }, |
2639 {17, true, "\003www\007twitter\003com", kTwitterHSTS, kTwitterComPins, DOMAIN_ TWITTER_COM }, | 1470 {17, true, "\003api\007twitter\003com", false, kTwitterCDNPins, DOMAIN_TWITTER _COM }, |
2640 {17, true, "\003api\007twitter\003com", kTwitterHSTS, kTwitterCDNPins, DOMAIN_ TWITTER_COM }, | 1471 {19, true, "\005oauth\007twitter\003com", false, kTwitterComPins, DOMAIN_TWITT ER_COM }, |
2641 {19, true, "\005oauth\007twitter\003com", kTwitterHSTS, kTwitterComPins, DOMAI N_TWITTER_COM }, | 1472 {20, true, "\006mobile\007twitter\003com", false, kTwitterComPins, DOMAIN_TWIT TER_COM }, |
2642 {20, true, "\006mobile\007twitter\003com", kTwitterHSTS, kTwitterComPins, DOMA IN_TWITTER_COM }, | 1473 {17, true, "\003dev\007twitter\003com", false, kTwitterComPins, DOMAIN_TWITTER _COM }, |
2643 {17, true, "\003dev\007twitter\003com", kTwitterHSTS, kTwitterComPins, DOMAIN_ TWITTER_COM }, | 1474 {22, true, "\010business\007twitter\003com", false, kTwitterComPins, DOMAIN_TW ITTER_COM }, |
2644 {22, true, "\010business\007twitter\003com", kTwitterHSTS, kTwitterComPins, DO MAIN_TWITTER_COM }, | |
2645 {22, true, "\010platform\007twitter\003com", false, kTwitterCDNPins, DOMAIN_TW ITTER_COM }, | 1475 {22, true, "\010platform\007twitter\003com", false, kTwitterCDNPins, DOMAIN_TW ITTER_COM }, |
2646 {15, true, "\003si0\005twimg\003com", false, kTwitterCDNPins, DOMAIN_TWIMG_COM }, | 1476 {15, true, "\003si0\005twimg\003com", false, kTwitterCDNPins, DOMAIN_TWIMG_COM }, |
2647 {23, true, "\010twimg0-a\010akamaihd\003net", false, kTwitterCDNPins, DOMAIN_A KAMAIHD_NET }, | 1477 {23, true, "\010twimg0-a\010akamaihd\003net", false, kTwitterCDNPins, DOMAIN_A KAMAIHD_NET }, |
2648 }; | 1478 }; |
2649 static const size_t kNumPreloadedSTS = ARRAYSIZE_UNSAFE(kPreloadedSTS); | 1479 static const size_t kNumPreloadedSTS = ARRAYSIZE_UNSAFE(kPreloadedSTS); |
2650 | 1480 |
2651 static const struct HSTSPreload kPreloadedSNISTS[] = { | 1481 static const struct HSTSPreload kPreloadedSNISTS[] = { |
2652 // These SNI-only domains must always use HTTPS. | |
2653 {11, false, "\005gmail\003com", true, kGooglePins, DOMAIN_GMAIL_COM }, | 1482 {11, false, "\005gmail\003com", true, kGooglePins, DOMAIN_GMAIL_COM }, |
2654 {16, false, "\012googlemail\003com", true, kGooglePins, DOMAIN_GOOGLEMAIL_COM }, | 1483 {16, false, "\012googlemail\003com", true, kGooglePins, DOMAIN_GOOGLEMAIL_COM }, |
2655 {15, false, "\003www\005gmail\003com", true, kGooglePins, DOMAIN_GMAIL_COM }, | 1484 {15, false, "\003www\005gmail\003com", true, kGooglePins, DOMAIN_GMAIL_COM }, |
2656 {20, false, "\003www\012googlemail\003com", true, kGooglePins, DOMAIN_GOOGLEMA IL_COM }, | 1485 {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. | |
2659 {22, true, "\020google-analytics\003com", false, kGooglePins, DOMAIN_GOOGLE_AN ALYTICS_COM }, | 1486 {22, true, "\020google-analytics\003com", false, kGooglePins, DOMAIN_GOOGLE_AN ALYTICS_COM }, |
2660 // www. requires SNI. | |
2661 {18, true, "\014googlegroups\003com", false, kGooglePins, DOMAIN_GOOGLEGROUPS_ COM }, | 1487 {18, true, "\014googlegroups\003com", false, kGooglePins, DOMAIN_GOOGLEGROUPS_ COM }, |
2662 }; | 1488 }; |
2663 static const size_t kNumPreloadedSNISTS = ARRAYSIZE_UNSAFE(kPreloadedSNISTS); | 1489 static const size_t kNumPreloadedSNISTS = ARRAYSIZE_UNSAFE(kPreloadedSNISTS); |
2664 | 1490 |
2665 // Returns the HSTSPreload entry for the |canonicalized_host| in |entries|, | 1491 #endif // NET_BASE_HSTS_PRELOADED_H_ |
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 |