summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authoragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-12 17:40:14 +0000
committeragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-12 17:40:14 +0000
commit236ca9fbfa1cc341bb185a74a7c390912e51cb71 (patch)
treeefea4ea40c5bf363ae09334d2622432e8ec89e21 /net
parent09bd103c2ad67af7e206a0045a082a6eb8b067d0 (diff)
downloadchromium_src-236ca9fbfa1cc341bb185a74a7c390912e51cb71.zip
chromium_src-236ca9fbfa1cc341bb185a74a7c390912e51cb71.tar.gz
chromium_src-236ca9fbfa1cc341bb185a74a7c390912e51cb71.tar.bz2
net: move HSTS preloaded and pinning info out of code.
This change moves information about HSTS preloaded and public key pinning, that were previously written in code, into external files that can be consumed by other programs. Those files are converted by a program (that is not part of the build process) into hsts_preloaded.h. In order to make this change easier to review, hsts_preloaded.h was created by concatenating public_key_hashes.h and transport_security_state.cc. Therefore, the diffs will show where the new, generated file differs from the previous code. public_key_hashes.h and public_key_hashes_check.go are removed and subsumed by hsts_preloaded.h. BUG=none TEST=net_unittests Review URL: https://chromiumcodereview.appspot.com/9863001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@132012 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/base/public_key_hashes_check.go235
-rw-r--r--net/base/transport_security_state.cc345
-rw-r--r--net/base/transport_security_state_static.certs (renamed from net/base/public_key_hashes.h)259
-rw-r--r--net/base/transport_security_state_static.h1471
-rw-r--r--net/base/transport_security_state_static.json267
-rw-r--r--net/base/transport_security_state_static_generate.go547
-rw-r--r--net/net.gyp1
7 files changed, 945 insertions, 2180 deletions
diff --git a/net/base/public_key_hashes_check.go b/net/base/public_key_hashes_check.go
deleted file mode 100644
index 61b4bcdd..0000000
--- a/net/base/public_key_hashes_check.go
+++ /dev/null
@@ -1,235 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// public_key_hashes_check.go runs tests on public_key_hashes.h. It's not run
-// automatically, but rather as part of the process of manually updating
-// public_key_hashes.h
-//
-// It verifies that each hash in the file is correct given the preceeding
-// certificate and that the name of the variable matches the name given in the
-// certifiate.
-//
-// Compile and run with:
-// % cd net/base
-// % 6g public_key_hashes_check.go && 6l public_key_hashes_check.6 && ./6.out ./public_key_hashes.h
-
-package main
-
-import (
- "bufio"
- "bytes"
- "crypto/sha1"
- "crypto/x509"
- "encoding/base64"
- "encoding/pem"
- "errors"
- "fmt"
- "io"
- "os"
- "strings"
-)
-
-const (
- PRECERT = iota
- INCERT = iota
- POSTCERT = iota
- POSTDECL = iota
-)
-
-var newLine = []byte("\n")
-var startOfCert = []byte("-----BEGIN CERTIFICATE")
-var endOfCert = []byte("-----END CERTIFICATE")
-var hashDecl = []byte("static const char kSPKIHash_")
-
-// matchNames returns true if the given variable name is a reasonable match for
-// the given CN.
-func matchNames(name, v string) error {
- words := strings.Split(name, " ")
- if len(words) == 0 {
- return errors.New("No words in certificate name")
- }
- firstWord := words[0]
- if strings.HasSuffix(firstWord, ",") {
- firstWord = firstWord[:len(firstWord)-1]
- }
- if pos := strings.Index(firstWord, "."); pos != -1 {
- firstWord = firstWord[:pos]
- }
- if pos := strings.Index(firstWord, "-"); pos != -1 {
- firstWord = firstWord[:pos]
- }
- if !strings.HasPrefix(v, firstWord) {
- return errors.New("The first word of the certificate name isn't a prefix of the variable name")
- }
-
- for i, word := range words {
- if word == "Class" && i+1 < len(words) {
- if strings.Index(v, word+words[i+1]) == -1 {
- return errors.New("Class specification doesn't appear in the variable name")
- }
- } else if len(word) == 1 && word[0] >= '0' && word[0] <= '9' {
- if strings.Index(v, word) == -1 {
- return errors.New("Number doesn't appear in the variable name")
- }
- } else if isImportantWordInCertificateName(word) {
- if strings.Index(v, word) == -1 {
- return errors.New(word + " doesn't appear in the variable name")
- }
- }
- }
-
- return nil
-}
-
-// isImportantWordInCertificateName returns true if w must be found in any
-// corresponding variable name.
-func isImportantWordInCertificateName(w string) bool {
- switch w {
- case "Universal", "Global", "EV", "G1", "G2", "G3", "G4", "G5":
- return true
- }
- return false
-}
-
-func main() {
- if len(os.Args) < 2 {
- fmt.Fprintf(os.Stderr, "Usage: %s <public_key_hashes.h>\n", os.Args[0])
- return
- }
-
- inFile, err := os.Open(os.Args[1])
- if err != nil {
- fmt.Fprintf(os.Stderr, "Failed to open input file: %s\n", err.Error())
- return
- }
-
- in := bufio.NewReader(inFile)
- defer inFile.Close()
-
- lineNo := 0
- var cert []byte
- state := PRECERT
- var x509Cert *x509.Certificate
- seenHashes := make(map[string]bool)
-
- for {
- lineNo++
- line, isPrefix, err := in.ReadLine()
- if isPrefix {
- fmt.Fprintf(os.Stderr, "Line %d is too long to process\n", lineNo)
- return
- }
- if err == io.EOF {
- return
- }
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error reading from input: %s\n", err.Error())
- return
- }
-
- switch state {
- case INCERT:
- cert = append(cert, line...)
- cert = append(cert, newLine...)
- case POSTDECL:
- trimmed := bytes.TrimSpace(line)
- if len(trimmed) < 8 || !bytes.HasPrefix(trimmed, []byte("\"sha1/")) {
- fmt.Fprintf(os.Stderr, "Line %d is immediately after a declation, but failed to find a hash on it\n", lineNo)
- return
- }
- trimmed = trimmed[6 : len(trimmed)-2]
- h := sha1.New()
- h.Write(x509Cert.RawSubjectPublicKeyInfo)
- shouldBe := base64.StdEncoding.EncodeToString(h.Sum(nil))
- if shouldBe != string(trimmed) {
- fmt.Fprintf(os.Stderr, "Line %d: hash should be %s, but found %s\n", lineNo, shouldBe, trimmed)
- return
- }
- if _, ok := seenHashes[shouldBe]; ok {
- fmt.Fprintf(os.Stderr, "Line %d: duplicated hash\n", lineNo)
- return
- }
- seenHashes[shouldBe] = true
- state = PRECERT
- x509Cert = nil
- }
-
- if bytes.HasPrefix(line, startOfCert) {
- switch state {
- case PRECERT:
- cert = append(cert, line...)
- cert = append(cert, newLine...)
- state = INCERT
- case INCERT:
- fmt.Fprintf(os.Stderr, "Found start of certificate while in certificate at line %d\n", lineNo)
- return
- case POSTCERT:
- fmt.Fprintf(os.Stderr, "Found start of certificate while while looking for hash at line %d\n", lineNo)
- return
- case POSTDECL:
- fmt.Fprintf(os.Stderr, "Found start of certificate while while looking for hash string at line %d\n", lineNo)
- return
- default:
- panic("bad state")
- }
- } else if bytes.HasPrefix(line, endOfCert) {
- switch state {
- case PRECERT:
- fmt.Fprintf(os.Stderr, "Found end of certificate without certificate at line %d\n", lineNo)
- return
- case INCERT:
- block, _ := pem.Decode(cert)
- if block == nil {
- fmt.Fprintf(os.Stderr, "Failed to decode certificate ending on line %d\n", lineNo)
- return
- }
- if x509Cert, err = x509.ParseCertificate(block.Bytes); err != nil {
- fmt.Fprintf(os.Stderr, "Failed to parse certificate ending on line %d: %s\n", lineNo, err.Error())
- return
- }
- cert = nil
- state = POSTCERT
- case POSTCERT:
- fmt.Fprintf(os.Stderr, "Found end of certificate while while looking for hash at line %d\n", lineNo)
- return
- case POSTDECL:
- fmt.Fprintf(os.Stderr, "Found end of certificate while while looking for hash string at line %d\n", lineNo)
- return
- default:
- panic("bad state")
- }
- } else if bytes.HasPrefix(line, hashDecl) {
- switch state {
- case PRECERT:
- // No problem here. Not all declations need a certificate
- case INCERT:
- fmt.Fprintf(os.Stderr, "Found declation at line %d, but missed the end of the certificate\n", lineNo)
- return
- case POSTCERT:
- varName := line[len(hashDecl):]
- for i, c := range varName {
- if c == '[' {
- varName = varName[:i]
- break
- }
- }
- name := x509Cert.Subject.CommonName
- if len(name) == 0 {
- name = x509Cert.Subject.Organization[0] + " " + x509Cert.Subject.OrganizationalUnit[0]
- }
- if err := matchNames(name, string(varName)); err != nil {
- fmt.Fprintf(os.Stderr, "Name failure on line %d: %s\n%s -> %s\n", lineNo, err, name, varName)
- return
- }
-
- state = POSTDECL
- case POSTDECL:
- fmt.Fprintf(os.Stderr, "Found declation at line %d, but missed the hash value of the previous one\n", lineNo)
- return
- default:
- panic("bad state")
- }
- }
- }
-}
diff --git a/net/base/transport_security_state.cc b/net/base/transport_security_state.cc
index 93b0254..b5fce7b 100644
--- a/net/base/transport_security_state.cc
+++ b/net/base/transport_security_state.cc
@@ -35,7 +35,6 @@
#include "googleurl/src/gurl.h"
#include "net/base/asn1_util.h"
#include "net/base/dns_util.h"
-#include "net/base/public_key_hashes.h"
#include "net/base/ssl_info.h"
#include "net/base/x509_certificate.h"
#include "net/http/http_util.h"
@@ -1147,349 +1146,7 @@ static bool HasPreload(const struct HSTSPreload* entries, size_t num_entries,
return false;
}
-// kNoRejectedPublicKeys is a placeholder for when no public keys are rejected.
-static const char* const kNoRejectedPublicKeys[] = {
- NULL,
-};
-
-static const char* const kGoogleAcceptableCerts[] = {
- kSPKIHash_VeriSignClass3,
- kSPKIHash_VeriSignClass3_G3,
- kSPKIHash_Google1024,
- kSPKIHash_Google2048,
- kSPKIHash_EquifaxSecureCA,
- NULL,
-};
-static const char* const kGoogleRejectedCerts[] = {
- kSPKIHash_Aetna,
- kSPKIHash_Intel,
- kSPKIHash_TCTrustCenter,
- kSPKIHash_Vodafone,
- NULL,
-};
-#define kGooglePins { \
- kGoogleAcceptableCerts, \
- kGoogleRejectedCerts, \
-}
-
-static const char* const kTorAcceptableCerts[] = {
- kSPKIHash_RapidSSL,
- kSPKIHash_DigiCertEVRoot,
- kSPKIHash_Tor1,
- kSPKIHash_Tor2,
- kSPKIHash_Tor3,
- NULL,
-};
-#define kTorPins { \
- kTorAcceptableCerts, \
- kNoRejectedPublicKeys, \
-}
-
-static const char* const kTwitterComAcceptableCerts[] = {
- kSPKIHash_VeriSignClass1,
- kSPKIHash_VeriSignClass3,
- kSPKIHash_VeriSignClass3_G4,
- kSPKIHash_VeriSignClass4_G3,
- kSPKIHash_VeriSignClass3_G3,
- kSPKIHash_VeriSignClass1_G3,
- kSPKIHash_VeriSignClass2_G3,
- kSPKIHash_VeriSignClass3_G2,
- kSPKIHash_VeriSignClass2_G2,
- kSPKIHash_VeriSignClass3_G5,
- kSPKIHash_VeriSignUniversal,
- kSPKIHash_GeoTrustGlobal,
- kSPKIHash_GeoTrustGlobal2,
- kSPKIHash_GeoTrustUniversal,
- kSPKIHash_GeoTrustUniversal2,
- kSPKIHash_GeoTrustPrimary,
- kSPKIHash_GeoTrustPrimary_G2,
- kSPKIHash_GeoTrustPrimary_G3,
- kSPKIHash_Twitter1,
- NULL,
-};
-#define kTwitterComPins { \
- kTwitterComAcceptableCerts, \
- kNoRejectedPublicKeys, \
-}
-
-// kTwitterCDNAcceptableCerts are the set of public keys valid for Twitter's
-// CDNs, which includes all the keys from kTwitterComAcceptableCerts.
-static const char* const kTwitterCDNAcceptableCerts[] = {
- kSPKIHash_VeriSignClass1,
- kSPKIHash_VeriSignClass3,
- kSPKIHash_VeriSignClass3_G4,
- kSPKIHash_VeriSignClass4_G3,
- kSPKIHash_VeriSignClass3_G3,
- kSPKIHash_VeriSignClass1_G3,
- kSPKIHash_VeriSignClass2_G3,
- kSPKIHash_VeriSignClass3_G2,
- kSPKIHash_VeriSignClass2_G2,
- kSPKIHash_VeriSignClass3_G5,
- kSPKIHash_VeriSignUniversal,
- kSPKIHash_GeoTrustGlobal,
- kSPKIHash_GeoTrustGlobal2,
- kSPKIHash_GeoTrustUniversal,
- kSPKIHash_GeoTrustUniversal2,
- kSPKIHash_GeoTrustPrimary,
- kSPKIHash_GeoTrustPrimary_G2,
- kSPKIHash_GeoTrustPrimary_G3,
- kSPKIHash_Twitter1,
-
- kSPKIHash_Entrust_2048,
- kSPKIHash_Entrust_EV,
- kSPKIHash_Entrust_G2,
- kSPKIHash_Entrust_SSL,
- kSPKIHash_AAACertificateServices,
- kSPKIHash_AddTrustClass1CARoot,
- kSPKIHash_AddTrustExternalCARoot,
- kSPKIHash_AddTrustPublicCARoot,
- kSPKIHash_AddTrustQualifiedCARoot,
- kSPKIHash_COMODOCertificationAuthority,
- kSPKIHash_SecureCertificateServices,
- kSPKIHash_TrustedCertificateServices,
- kSPKIHash_UTNDATACorpSGC,
- kSPKIHash_UTNUSERFirstClientAuthenticationandEmail,
- kSPKIHash_UTNUSERFirstHardware,
- kSPKIHash_UTNUSERFirstObject,
- kSPKIHash_GTECyberTrustGlobalRoot,
- NULL,
-};
-#define kTwitterCDNPins { \
- kTwitterCDNAcceptableCerts, \
- kNoRejectedPublicKeys, \
-}
-
-// kTestAcceptableCerts doesn't actually match any public keys and is used
-// with "pinningtest.appspot.com", below, to test if pinning is active.
-static const char* const kTestAcceptableCerts[] = {
- "sha1/AAAAAAAAAAAAAAAAAAAAAAAAAAA=",
- NULL,
-};
-#define kTestPins { \
- kTestAcceptableCerts, \
- kNoRejectedPublicKeys, \
-}
-
-#define kNoPins { \
- NULL, NULL, \
-}
-
-#if defined(OS_CHROMEOS)
- static const bool kTwitterHSTS = true;
-#else
- static const bool kTwitterHSTS = false;
-#endif
-
-// In the medium term this list is likely to just be hardcoded here. This
-// slightly odd form removes the need for additional relocations records.
-static const struct HSTSPreload kPreloadedSTS[] = {
- // (*.)google.com, iff using SSL must use an acceptable certificate.
- {12, true, "\006google\003com", false, kGooglePins,
- DOMAIN_GOOGLE_COM },
- {25, true, "\013pinningtest\007appspot\003com", false,
- kTestPins, DOMAIN_APPSPOT_COM },
- // Now we force HTTPS for subtrees of google.com.
- {19, true, "\006health\006google\003com", true, kGooglePins,
- DOMAIN_GOOGLE_COM },
- {21, true, "\010checkout\006google\003com", true, kGooglePins,
- DOMAIN_GOOGLE_COM },
- {19, true, "\006chrome\006google\003com", true, kGooglePins,
- DOMAIN_GOOGLE_COM },
- {17, true, "\004docs\006google\003com", true, kGooglePins,
- DOMAIN_GOOGLE_COM },
- {18, true, "\005sites\006google\003com", true, kGooglePins,
- DOMAIN_GOOGLE_COM },
- {25, true, "\014spreadsheets\006google\003com", true,
- kGooglePins, DOMAIN_GOOGLE_COM },
- {22, false, "\011appengine\006google\003com", true,
- kGooglePins, DOMAIN_GOOGLE_COM },
- {22, true, "\011encrypted\006google\003com", true, kGooglePins,
- DOMAIN_GOOGLE_COM },
- {21, true, "\010accounts\006google\003com", true, kGooglePins,
- DOMAIN_GOOGLE_COM },
- {21, true, "\010profiles\006google\003com", true, kGooglePins,
- DOMAIN_GOOGLE_COM },
- {17, true, "\004mail\006google\003com", true, kGooglePins,
- DOMAIN_GOOGLE_COM },
- {23, true, "\012talkgadget\006google\003com", true,
- kGooglePins, DOMAIN_GOOGLE_COM },
- {17, true, "\004talk\006google\003com", true, kGooglePins,
- DOMAIN_GOOGLE_COM },
- {29, true, "\020hostedtalkgadget\006google\003com", true,
- kGooglePins, DOMAIN_GOOGLE_COM },
- {17, true, "\004plus\006google\003com", true, kGooglePins,
- DOMAIN_GOOGLE_COM },
- // Other Google-related domains that must use HTTPS.
- {20, true, "\006market\007android\003com", true, kGooglePins,
- DOMAIN_ANDROID_COM },
- {26, true, "\003ssl\020google-analytics\003com", true,
- kGooglePins, DOMAIN_GOOGLE_ANALYTICS_COM },
- {18, true, "\005drive\006google\003com", true, kGooglePins,
- DOMAIN_GOOGLE_COM },
- {16, true, "\012googleplex\003com", true, kGooglePins,
- DOMAIN_GOOGLEPLEX_COM },
- {19, true, "\006groups\006google\003com", true, kGooglePins,
- DOMAIN_GOOGLE_COM },
- {17, true, "\004apis\006google\003com", true, kGooglePins,
- DOMAIN_GOOGLE_COM },
- // chart.apis.google.com is *not* HSTS because the certificate doesn't match
- // and there are lots of links out there that still use the name. The correct
- // hostname for this is chart.googleapis.com.
- {23, true, "\005chart\004apis\006google\003com", false, kGooglePins,
- DOMAIN_GOOGLE_COM},
-
- // Other Google-related domains that must use an acceptable certificate
- // iff using SSL.
- {11, true, "\005ytimg\003com", false, kGooglePins,
- DOMAIN_YTIMG_COM },
- {23, true, "\021googleusercontent\003com", false, kGooglePins,
- DOMAIN_GOOGLEUSERCONTENT_COM },
- {13, true, "\007youtube\003com", false, kGooglePins,
- DOMAIN_YOUTUBE_COM },
- {16, true, "\012googleapis\003com", false, kGooglePins,
- DOMAIN_GOOGLEAPIS_COM },
- {22, true, "\020googleadservices\003com", false, kGooglePins,
- DOMAIN_GOOGLEADSERVICES_COM },
- {16, true, "\012googlecode\003com", false, kGooglePins,
- DOMAIN_GOOGLECODE_COM },
- {13, true, "\007appspot\003com", false, kGooglePins,
- DOMAIN_APPSPOT_COM },
- {23, true, "\021googlesyndication\003com", false, kGooglePins,
- DOMAIN_GOOGLESYNDICATION_COM },
- {17, true, "\013doubleclick\003net", false, kGooglePins,
- DOMAIN_DOUBLECLICK_NET },
- {17, true, "\003ssl\007gstatic\003com", false, kGooglePins,
- DOMAIN_GSTATIC_COM },
- // Exclude the learn.doubleclick.net subdomain because it uses a different
- // CA.
- {23, true, "\005learn\013doubleclick\003net", false, kNoPins, DOMAIN_NOT_PINNED },
- // Now we force HTTPS for other sites that have requested it.
- {16, false, "\003www\006paypal\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {16, false, "\003www\006elanex\003biz", true, kNoPins, DOMAIN_NOT_PINNED },
- {12, true, "\006jottit\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {19, true, "\015sunshinepress\003org", true, kNoPins, DOMAIN_NOT_PINNED },
- {21, false, "\003www\013noisebridge\003net", true, kNoPins,
- DOMAIN_NOT_PINNED },
- {10, false, "\004neg9\003org", true, kNoPins, DOMAIN_NOT_PINNED },
- {12, true, "\006riseup\003net", true, kNoPins, DOMAIN_NOT_PINNED },
- {11, false, "\006factor\002cc", true, kNoPins, DOMAIN_NOT_PINNED },
- {22, false, "\007members\010mayfirst\003org", true, kNoPins, DOMAIN_NOT_PINNED },
- {22, false, "\007support\010mayfirst\003org", true, kNoPins, DOMAIN_NOT_PINNED },
- {17, false, "\002id\010mayfirst\003org", true, kNoPins, DOMAIN_NOT_PINNED },
- {20, false, "\005lists\010mayfirst\003org", true, kNoPins, DOMAIN_NOT_PINNED },
- {19, true, "\015splendidbacon\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {28, false, "\016aladdinschools\007appspot\003com", true, kNoPins,
- DOMAIN_NOT_PINNED },
- {14, true, "\011ottospora\002nl", true, kNoPins, DOMAIN_NOT_PINNED },
- {25, false, "\003www\017paycheckrecords\003com", true, kNoPins,
- DOMAIN_NOT_PINNED },
- {14, false, "\010lastpass\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {18, false, "\003www\010lastpass\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {14, true, "\010keyerror\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {13, false, "\010entropia\002de", true, kNoPins, DOMAIN_NOT_PINNED },
- {17, false, "\003www\010entropia\002de", true, kNoPins, DOMAIN_NOT_PINNED },
- {11, true, "\005romab\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {16, false, "\012logentries\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {20, false, "\003www\012logentries\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {12, true, "\006stripe\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {27, true, "\025cloudsecurityalliance\003org", true, kNoPins,
- DOMAIN_NOT_PINNED },
- {15, true, "\005login\004sapo\002pt", true, kNoPins, DOMAIN_NOT_PINNED },
- {19, true, "\015mattmccutchen\003net", true, kNoPins, DOMAIN_NOT_PINNED },
- {11, true, "\006betnet\002fr", true, kNoPins, DOMAIN_NOT_PINNED },
- {13, true, "\010uprotect\002it", true, kNoPins, DOMAIN_NOT_PINNED },
- {14, false, "\010squareup\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {9, true, "\004cert\002se", true, kNoPins, DOMAIN_NOT_PINNED },
- {11, true, "\006crypto\002is", true, kNoPins, DOMAIN_NOT_PINNED },
- {20, true, "\005simon\007butcher\004name", true, kNoPins, DOMAIN_NOT_PINNED },
- {10, true, "\004linx\003net", true, kNoPins, DOMAIN_NOT_PINNED },
- {13, false, "\007dropcam\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {17, false, "\003www\007dropcam\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {30, true, "\010ebanking\014indovinabank\003com\002vn", true, kNoPins,
- DOMAIN_NOT_PINNED },
- {13, false, "\007epoxate\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {16, false, "\012torproject\003org", true, kTorPins,
- DOMAIN_TORPROJECT_ORG },
- {21, true, "\004blog\012torproject\003org", true, kTorPins,
- DOMAIN_TORPROJECT_ORG },
- {22, true, "\005check\012torproject\003org", true, kTorPins,
- DOMAIN_TORPROJECT_ORG },
- {20, true, "\003www\012torproject\003org", true, kTorPins,
- DOMAIN_TORPROJECT_ORG },
- {22, true, "\003www\014moneybookers\003com", true, kNoPins,
- DOMAIN_NOT_PINNED },
- {17, false, "\013ledgerscope\003net", true, kNoPins, DOMAIN_NOT_PINNED },
- {21, false, "\003www\013ledgerscope\003net", true, kNoPins,
- DOMAIN_NOT_PINNED },
- {10, false, "\004kyps\003net", true, kNoPins, DOMAIN_NOT_PINNED },
- {14, false, "\003www\004kyps\003net", true, kNoPins, DOMAIN_NOT_PINNED },
- {17, true, "\003app\007recurly\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {17, true, "\003api\007recurly\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {13, false, "\007greplin\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {17, false, "\003www\007greplin\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {27, true, "\006luneta\016nearbuysystems\003com", true, kNoPins,
- DOMAIN_NOT_PINNED },
- {12, true, "\006ubertt\003org", true, kNoPins, DOMAIN_NOT_PINNED },
- {9, true, "\004pixi\002me", true, kNoPins, DOMAIN_NOT_PINNED },
- {14, true, "\010grepular\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {16, false , "\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {20, false , "\003www\012mydigipass\003com", true, kNoPins,
- DOMAIN_NOT_PINNED },
- {26, false , "\011developer\012mydigipass\003com", true, kNoPins,
- DOMAIN_NOT_PINNED },
- {30, false , "\003www\011developer\012mydigipass\003com", true, kNoPins,
- DOMAIN_NOT_PINNED },
- {24, false , "\007sandbox\012mydigipass\003com", true, kNoPins,
- DOMAIN_NOT_PINNED },
- {28, false , "\003www\007sandbox\012mydigipass\003com", true, kNoPins,
- DOMAIN_NOT_PINNED },
- {12, true, "\006crypto\003cat", true, kNoPins, DOMAIN_NOT_PINNED },
- {25, true, "\014bigshinylock\006minazo\003net", true, kNoPins,
- DOMAIN_NOT_PINNED },
- {10, true, "\005crate\002io", true, kNoPins, DOMAIN_NOT_PINNED },
-
- {13, false, "\007twitter\003com", kTwitterHSTS,
- kTwitterComPins, DOMAIN_TWITTER_COM },
- {17, true, "\003www\007twitter\003com", kTwitterHSTS,
- kTwitterComPins, DOMAIN_TWITTER_COM },
- {17, true, "\003api\007twitter\003com", kTwitterHSTS,
- kTwitterCDNPins, DOMAIN_TWITTER_COM },
- {19, true, "\005oauth\007twitter\003com", kTwitterHSTS,
- kTwitterComPins, DOMAIN_TWITTER_COM },
- {20, true, "\006mobile\007twitter\003com", kTwitterHSTS,
- kTwitterComPins, DOMAIN_TWITTER_COM },
- {17, true, "\003dev\007twitter\003com", kTwitterHSTS,
- kTwitterComPins, DOMAIN_TWITTER_COM },
- {22, true, "\010business\007twitter\003com", kTwitterHSTS,
- kTwitterComPins, DOMAIN_TWITTER_COM },
- {22, true, "\010platform\007twitter\003com", false,
- kTwitterCDNPins, DOMAIN_TWITTER_COM },
- {15, true, "\003si0\005twimg\003com", false, kTwitterCDNPins,
- DOMAIN_TWIMG_COM },
- {23, true, "\010twimg0-a\010akamaihd\003net", false,
- kTwitterCDNPins, DOMAIN_AKAMAIHD_NET },
-};
-static const size_t kNumPreloadedSTS = ARRAYSIZE_UNSAFE(kPreloadedSTS);
-
-static const struct HSTSPreload kPreloadedSNISTS[] = {
- // These SNI-only domains must always use HTTPS.
- {11, false, "\005gmail\003com", true, kGooglePins,
- DOMAIN_GMAIL_COM },
- {16, false, "\012googlemail\003com", true, kGooglePins,
- DOMAIN_GOOGLEMAIL_COM },
- {15, false, "\003www\005gmail\003com", true, kGooglePins,
- DOMAIN_GMAIL_COM },
- {20, false, "\003www\012googlemail\003com", true, kGooglePins,
- DOMAIN_GOOGLEMAIL_COM },
- // These SNI-only domains must use an acceptable certificate iff using
- // HTTPS.
- {22, true, "\020google-analytics\003com", false, kGooglePins,
- DOMAIN_GOOGLE_ANALYTICS_COM },
- // www. requires SNI.
- {18, true, "\014googlegroups\003com", false, kGooglePins,
- DOMAIN_GOOGLEGROUPS_COM },
-};
-static const size_t kNumPreloadedSNISTS = ARRAYSIZE_UNSAFE(kPreloadedSNISTS);
+#include "net/base/transport_security_state_static.h"
// Returns the HSTSPreload entry for the |canonicalized_host| in |entries|,
// or NULL if there is none. Prefers exact hostname matches to those that
diff --git a/net/base/public_key_hashes.h b/net/base/transport_security_state_static.certs
index c7db2f0..0857bfb 100644
--- a/net/base/public_key_hashes.h
+++ b/net/base/transport_security_state_static.certs
@@ -1,15 +1,18 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
-#ifndef NET_BASE_PUBLIC_KEY_HASHES_
-#define NET_BASE_PUBLIC_KEY_HASHES_
-#pragma once
+# This file contains pinned certificates to be used in conjunction with
+# hsts_preloaded.json. See the comments at the beginning of that file for
+# details.
-// This file contains SubjectPublicKeyInfo hashes for public key pinning. The
-// hashes are base64 encoded, SHA1 digests.
+# Each entry consists of a line containing the name of the pin followed either
+# by a hash in the format "sha1/" + base64(hash), or a PEM encoded certificate.
-#if 0
+TestSPKI
+sha1/AAAAAAAAAAAAAAAAAAAAAAAAAAA=
+
+VeriSignClass3
-----BEGIN CERTIFICATE-----
MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG
A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
@@ -24,11 +27,8 @@ CSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i
2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWXbj9T/UWZYB2oK0z5XqcJ
2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/D/xwzoiQ
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_VeriSignClass3[] =
- "sha1/4n972HfV354KP560yw4uqe/baXc=";
-#if 0
+VeriSignClass3_G3
-----BEGIN CERTIFICATE-----
MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
@@ -53,11 +53,8 @@ DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt
TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_VeriSignClass3_G3[] =
- "sha1/IvGeLsbqzPxdI0b0wuj2xVTdXgc=";
-#if 0
+Google1024
-----BEGIN CERTIFICATE-----
MIICsDCCAhmgAwIBAgIDC2dxMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
@@ -75,15 +72,11 @@ BZqrocb6ghwYB8TrgbCoZutJqOkM0ymt9e8kTP3kS8p/XmOrmSfLnzYhLLkQYGfN
0rTw8Ktx5YtaiScRhKqOv5nwnQkhClIZmloJ0pC3+gz4fniisIWvXEyZ2VxVKfml
UUIuOss4jHg7y/j7lYe8vJD5UDI=
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_Google1024[] =
- "sha1/QMVAHW+MuvCLAO3vse6H0AWzuc0=";
-// Not yet used publicly.
-static const char kSPKIHash_Google2048[] =
- "sha1/AbkhxY0L343gKf+cki7NVWp+ozk=";
+Google2048
+sha1/AbkhxY0L343gKf+cki7NVWp+ozk=
-#if 0
+EquifaxSecureCA
-----BEGIN CERTIFICATE-----
MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
@@ -103,11 +96,8 @@ A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_EquifaxSecureCA[] =
- "sha1/SOZo+SvSspXXR9gjIBBPM5iQn9Q=";
-#if 0
+Aetna
-----BEGIN CERTIFICATE-----
MIICsjCCAhugAwIBAgIDBe3YMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
@@ -125,11 +115,8 @@ UG3UYbN76xiF9FDRzWTs5Mvv4Psvf2kk426slzNO0ukFAsmwqN1mA/P9Nc4FlMMC
YtcnLNwC/syEYdQBOJjxfTVGTqh5q6jDs7S3rPJv8mrFk8ldC8PxU1ZJVfSlFCDn
6diMDgvOAJfUeJlIRLGu2k/ksI0Y1w==
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_Aetna[] =
- "sha1/klKqFN6/gK4wqtlOYDhwJKVDLxo=";
-#if 0
+GeoTrustGlobal
-----BEGIN CERTIFICATE-----
MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
@@ -151,11 +138,8 @@ AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDITtZDOLC5MH0Y0FWDomrL
NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W
b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_GeoTrustGlobal[] =
- "sha1/wHqYaI2J+6sFZAwRfap9ZbjKzE4=";
-#if 0
+GeoTrustPrimary
-----BEGIN CERTIFICATE-----
MIIDizCCAvSgAwIBAgIDDW5iMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
@@ -177,11 +161,8 @@ KoZIhvcNAQEFBQADgYEAr/MO1nKrx6mXyiprhDneeanwgeUIZ6vXLyACAXEMBCLJ
HoiVA8lJOq9nCEmw1Qj1ID2AkaDFh6P7yaMXkfmoL67pD9+Wcg91F4BdeAFNnx9t
e9j1QjgjGpmT9IO+OzV05zcTNXqstLaQgmwnpODsnjW9v+UpoUefWzL86Zl9Kzk=
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_GeoTrustPrimary[] =
- "sha1/sBmJ5+/7Sq/LFI9YRjl2IkFQ4bo=";
-#if 0
+Intel
-----BEGIN CERTIFICATE-----
MIIFijCCBHKgAwIBAgIKYSCKYgAAAAAACDANBgkqhkiG9w0BAQUFADBSMQswCQYD
VQQGEwJVUzEaMBgGA1UEChMRSW50ZWwgQ29ycG9yYXRpb24xJzAlBgNVBAMTHklu
@@ -214,11 +195,8 @@ xmH3droUmMJI0/aZJHsLtjbjFnNsHDNrJZX1vxlM78Lb1hjskTENPmhbVbfTj5i/
ZGnhv4tmI8QZPCNtcegXJrfhRl2D9bWpdTOPrWiLDUqzy1Z6KL7TcOS/PCl8RHCJ
XkPau/thTQCpIoDa2+c+3XA++gRTfAQ4svTO260N
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_Intel[] =
- "sha1/DsYq91myCBCQJW/D3f2KZjEwK8U=";
-#if 0
+TCTrustCenter
-----BEGIN CERTIFICATE-----
MIIDWzCCAsSgAwIBAgIDCaxIMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
@@ -239,11 +217,8 @@ KoZIhvcNAQEFBQADgYEAVKyJLbJha83PggEit8+dzh50wIsKXpTV2K6K4HnUI1kh
xqocLVfQORluC+LS7L78D2EKTWLZ8WNujiP6DbbIPSTsMasuiBMQMBUlJMUqsp/M
XmQJgIGAbxsr19MY6mmB30oWuo4cjHnkMzSCfhcON6Rxvbjijk2qCWXkk2T2HAk=
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_TCTrustCenter[] =
- "sha1/gzuEEAB/bkqdQS3EIjk2by7lW+k=";
-#if 0
+Vodafone
-----BEGIN CERTIFICATE-----
MIIDJDCCAo2gAwIBAgIDBfw3MA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
@@ -263,11 +238,8 @@ AQUFAAOBgQCs37zuSY/KkPigCvJevu+ewWy9GP2bFZi5EaxKuHGF+tYFZUNkyc06
ACYMM3ADPM6dVUYeXIDZnPfV8BJFCpdoAHkSNlg341AVjabCOWtzOYolBn0ua8Wi
BM471XfzzXD7yMliek9J4fUn2vQU7MYgEkSAA53ZkMScGDkA/c1wMQ==
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_Vodafone[] =
- "sha1/DX/hXFUUNmiZ/EDWIgjvIuvRFRw=";
-#if 0
+RapidSSL
-----BEGIN CERTIFICATE-----
MIID1TCCAr2gAwIBAgIDAjbRMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
@@ -291,11 +263,8 @@ SUNjpWxOJ4cl61tt/qJ/OCjgNqutOaWlYsS3XFgsql0BYKZiZ6PAx2Ij9OdsRu61
knYYCnwPLKbK3opie9jzzl9ovY8+wXS7FXI6FoOpC+ZNmZzYV+yoAVHHb1c0XqtK
LEL2TxyJeN4mTvVvk0wVaydWTQBUbHq3tw==
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_RapidSSL[] =
- "sha1/o5OZxATDsgmwgcIfIWIneMJ0jkw=";
-#if 0
+DigiCertEVRoot
-----BEGIN CERTIFICATE-----
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
@@ -319,19 +288,15 @@ Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
+OkuE6N36B9K
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_DigiCertEVRoot[] =
- "sha1/gzF+YoVCU9bXeDGQ7JGQVumRueM=";
-// Not public
-static const char kSPKIHash_Tor1[] =
- "sha1/juNxSTv9UANmpC9kF5GKpmWNx3Y=";
-static const char kSPKIHash_Tor2[] =
- "sha1/lia43lPolzSPVIq34Dw57uYcLD8=";
-static const char kSPKIHash_Tor3[] =
- "sha1/rzEyQIKOh77j87n5bjWUNguXF8Y=";
+Tor1
+sha1/juNxSTv9UANmpC9kF5GKpmWNx3Y=
+Tor2
+sha1/lia43lPolzSPVIq34Dw57uYcLD8=
+Tor3
+sha1/rzEyQIKOh77j87n5bjWUNguXF8Y=
-#if 0
+VeriSignClass1
-----BEGIN CERTIFICATE-----
MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ
BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh
@@ -347,11 +312,8 @@ EWx8QszznC7EBz8UsA9P/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5
FvjqBUuUfx3CHMjjt/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89Fx
lA==
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_VeriSignClass1[] =
- "sha1/I0PRSKJViZuUfUYaeX7ATP7RcLc=";
-#if 0
+VeriSignClass3_G4
-----BEGIN CERTIFICATE-----
MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
@@ -373,11 +335,8 @@ kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC
4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga
FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_VeriSignClass3_G4[] =
- "sha1/7WYxNdMb1OymFMQp4xkGn5TBJlA=";
-#if 0
+VeriSignClass4_G3
-----BEGIN CERTIFICATE-----
MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
@@ -402,11 +361,8 @@ fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c
2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/
bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_VeriSignClass4_G3[] =
- "sha1/PANDaGiVHPNpKri0Jtq6j+ki5b0=";
-#if 0
+VeriSignClass1_G3
-----BEGIN CERTIFICATE-----
MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw
CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
@@ -431,11 +387,8 @@ ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs
pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4
E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g==
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_VeriSignClass1_G3[] =
- "sha1/VRmyeKyygdftp6vBg5nDu2kEJLU=";
-#if 0
+VeriSignClass2_G3
-----BEGIN CERTIFICATE-----
MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ
BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy
@@ -460,11 +413,8 @@ sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI
sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP
cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_VeriSignClass2_G3[] =
- "sha1/Wr7Fddyu87COJxlD/H8lDD32YeM=";
-#if 0
+VeriSignClass3_G2
-----BEGIN CERTIFICATE-----
MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
@@ -484,11 +434,8 @@ U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i
F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY
oJ2daZH9
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_VeriSignClass3_G2[] =
- "sha1/GiG0lStik84Ys2XsnA6TTLOB5tQ=";
-#if 0
+VeriSignClass2_G2
-----BEGIN CERTIFICATE-----
MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQsw
CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0Ns
@@ -508,11 +455,8 @@ nb3/7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX
rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnIn
jBJ7xUS0rg==
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_VeriSignClass2_G2[] =
- "sha1/Eje6RRfurSkm/cHN/r7t8t7ZFFw=";
-#if 0
+VeriSignClass3_G5
-----BEGIN CERTIFICATE-----
MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
@@ -541,11 +485,8 @@ WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_VeriSignClass3_G5[] =
- "sha1/sYEIGhmkwJQf+uiVKMEkyZs0rMc=";
-#if 0
+VeriSignUniversal
-----BEGIN CERTIFICATE-----
MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB
vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
@@ -574,15 +515,11 @@ BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR
lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3
7M2CYfE45k+XmCpajQ==
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_VeriSignUniversal[] =
- "sha1/u8I+KQuzKHcdrT6iTb30I70GsD0=";
-// Not public
-static const char kSPKIHash_Twitter1[] =
- "sha1/Vv7zwhR9TtOIN/29MFI4cgHld40=";
+Twitter1
+sha1/Vv7zwhR9TtOIN/29MFI4cgHld40=
-#if 0
+GeoTrustGlobal2
-----BEGIN CERTIFICATE-----
MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW
MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs
@@ -604,11 +541,8 @@ abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF
I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz
4iIprn2DQKi6bA==
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_GeoTrustGlobal2[] =
- "sha1/cTg28gIxU0crbrplRqkQFVggBQk=";
-#if 0
+GeoTrustUniversal
-----BEGIN CERTIFICATE-----
MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW
MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy
@@ -640,11 +574,8 @@ ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt
DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm
bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw=
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_GeoTrustUniversal[] =
- "sha1/h+hbY1PGI6MSjLD/u/VR/lmADiI=";
-#if 0
+GeoTrustUniversal2
-----BEGIN CERTIFICATE-----
MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW
MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy
@@ -676,11 +607,8 @@ OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH
6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX
QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_GeoTrustUniversal2[] =
- "sha1/Xk9ThoXdT57KX9wNRW99UbHcm3s=";
-#if 0
+GeoTrustPrimary_G2
-----BEGIN CERTIFICATE-----
MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL
MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj
@@ -698,11 +626,8 @@ CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT
qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz
rD6ogRLQy7rQkgu2npaqBA+K
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_GeoTrustPrimary_G2[] =
- "sha1/vb6nG6txV/nkddlU0rcngBqCJoI=";
-#if 0
+GeoTrustPrimary_G3
-----BEGIN CERTIFICATE-----
MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB
mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT
@@ -727,11 +652,8 @@ AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH
SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G
spki4cErx5z481+oghLrGREt
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_GeoTrustPrimary_G3[] =
- "sha1/nKmNAK90Dd2BgNITRaWLjy6UONY=";
-#if 0
+Entrust_2048
-----BEGIN CERTIFICATE-----
MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u
ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp
@@ -753,11 +675,8 @@ zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT
J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e
nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE=
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_Entrust_2048[] =
- "sha1/VeSB0RGAvtiJuQijMfmhJAkWuXA=";
-#if 0
+Entrust_EV
-----BEGIN CERTIFICATE-----
MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC
VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0
@@ -785,11 +704,8 @@ AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP
eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m
0vdXcDazv/wor3ElhVsT/h5/WrQ8
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_Entrust_EV[] =
- "sha1/ukKwgYhTiB2GY71MwF4I/upuu3c=";
-#if 0
+Entrust_G2
-----BEGIN CERTIFICATE-----
MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC
VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50
@@ -815,11 +731,8 @@ Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v
nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH
VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g==
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_Entrust_G2[] =
- "sha1/qzDTr0vY8WtYae5FaSnahLhzlIg=";
-#if 0
+Entrust_SSL
-----BEGIN CERTIFICATE-----
MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC
VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u
@@ -848,11 +761,8 @@ hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN
95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd
2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_Entrust_SSL[] =
- "sha1/8BdiE1U9s/8KAGv7UISX8+1i0Bo=";
-#if 0
+AAACertificateServices
-----BEGIN CERTIFICATE-----
MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
@@ -878,11 +788,8 @@ G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_AAACertificateServices[] =
- "sha1/xDAoxdPjCAwQRIssd7okU5dgu/k=";
-#if 0
+AddTrustClass1CARoot
-----BEGIN CERTIFICATE-----
MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU
MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
@@ -907,11 +814,8 @@ eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl
pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA
WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_AddTrustClass1CARoot[] =
- "sha1/i9vXzKBoU0IW9MErJUT8Apyli0c=";
-#if 0
+AddTrustExternalCARoot
-----BEGIN CERTIFICATE-----
MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
@@ -937,11 +841,8 @@ Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_AddTrustExternalCARoot[] =
- "sha1/T5x9IXmcrQ7YuQxXnxoCmeeQ84c=";
-#if 0
+AddTrustPublicCARoot
-----BEGIN CERTIFICATE-----
MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU
MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
@@ -966,11 +867,8 @@ GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh
4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm
XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY=
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_AddTrustPublicCARoot[] =
- "sha1/qFdl1ugyyMUZY3Namhd0OoHf7i4=";
-#if 0
+AddTrustQualifiedCARoot
-----BEGIN CERTIFICATE-----
MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU
MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
@@ -996,11 +894,8 @@ P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y
iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no
xqE=
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_AddTrustQualifiedCARoot[] =
- "sha1/vOS3IxJVmOVjQRkcUOS2R8J2Bdc=";
-#if 0
+COMODOCertificationAuthority
-----BEGIN CERTIFICATE-----
MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB
gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
@@ -1026,11 +921,8 @@ zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd
BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB
ZQ==
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_COMODOCertificationAuthority[] =
- "sha1/EeSR0cnkwOuazs9zVF3h8agwPsM=";
-#if 0
+SecureCertificateServices
-----BEGIN CERTIFICATE-----
MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb
MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
@@ -1056,11 +948,8 @@ gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ
aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl
izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk=
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_SecureCertificateServices[] =
- "sha1/PLQahC71XPIaPaVKyNG+OQh2N7w=";
-#if 0
+TrustedCertificateServices
-----BEGIN CERTIFICATE-----
MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb
MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
@@ -1086,11 +975,8 @@ jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+
xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn
dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_TrustedCertificateServices[] =
- "sha1//nLI678ML7sOJhOTkzwsqY3cJJQ=";
-#if 0
+UTNDATACorpSGC
-----BEGIN CERTIFICATE-----
MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB
kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
@@ -1117,11 +1003,8 @@ KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv
2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3
mfnGV/TJVTl4uix5yaaIK/QI
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_UTNDATACorpSGC[] =
- "sha1/UzLRs89/+uDxoF2FTpLSnkUdtE8=";
-#if 0
+UTNUSERFirstClientAuthenticationandEmail
-----BEGIN CERTIFICATE-----
MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCB
rjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
@@ -1149,11 +1032,8 @@ rfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarVNZ1yQAOJujEdxRBoUp7fooXFXAim
eOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gk
USeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ=
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_UTNUSERFirstClientAuthenticationandEmail[] =
- "sha1/iYJnfcSdJnAAS7RQSHzePa4Ebn0=";
-#if 0
+UTNUSERFirstHardware
-----BEGIN CERTIFICATE-----
MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
@@ -1180,11 +1060,8 @@ CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_UTNUSERFirstHardware[] =
- "sha1/oXJfJhsomEOVXQc31YWWnUvSw0U=";
-#if 0
+UTNUSERFirstObject
-----BEGIN CERTIFICATE-----
MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCB
lTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
@@ -1211,11 +1088,8 @@ mMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU
81OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCGhU3IfdeLA/5u1fedFqySLKAj5ZyR
Uh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g=
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_UTNUSERFirstObject[] =
- "sha1/2u1kdBScFDyr3ZmpvVsoTYs8ydg=";
-#if 0
+GTECyberTrustGlobalRoot
-----BEGIN CERTIFICATE-----
MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD
VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv
@@ -1231,8 +1105,3 @@ GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9
3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P
lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/
-----END CERTIFICATE-----
-#endif
-static const char kSPKIHash_GTECyberTrustGlobalRoot[] =
- "sha1/WXkS3mF11m/EI7d3E3THlt5viHI=";
-
-#endif // NET_BASE_PUBLIC_KEY_HASHES_
diff --git a/net/base/transport_security_state_static.h b/net/base/transport_security_state_static.h
index ce2c713..8166168 100644
--- a/net/base/transport_security_state_static.h
+++ b/net/base/transport_security_state_static.h
@@ -1,14 +1,19 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef NET_BASE_PUBLIC_KEY_HASHES_
-#define NET_BASE_PUBLIC_KEY_HASHES_
+// This file is automatically generated by transport_security_state_static_generate.go
+
+#ifndef NET_BASE_TRANSPORT_SECURITY_STATE_STATIC_H_
+#define NET_BASE_TRANSPORT_SECURITY_STATE_STATIC_H_
#pragma once
-// This file contains SubjectPublicKeyInfo hashes for public key pinning. The
+// These are SubjectPublicKeyInfo hashes for public key pinning. The
// hashes are base64 encoded, SHA1 digests.
+static const char kSPKIHash_TestSPKI[] =
+ "sha1/AAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+
#if 0
-----BEGIN CERTIFICATE-----
MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG
@@ -79,7 +84,6 @@ UUIuOss4jHg7y/j7lYe8vJD5UDI=
static const char kSPKIHash_Google1024[] =
"sha1/QMVAHW+MuvCLAO3vse6H0AWzuc0=";
-// Not yet used publicly.
static const char kSPKIHash_Google2048[] =
"sha1/AbkhxY0L343gKf+cki7NVWp+ozk=";
@@ -323,11 +327,12 @@ vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
static const char kSPKIHash_DigiCertEVRoot[] =
"sha1/gzF+YoVCU9bXeDGQ7JGQVumRueM=";
-// Not public
static const char kSPKIHash_Tor1[] =
"sha1/juNxSTv9UANmpC9kF5GKpmWNx3Y=";
+
static const char kSPKIHash_Tor2[] =
"sha1/lia43lPolzSPVIq34Dw57uYcLD8=";
+
static const char kSPKIHash_Tor3[] =
"sha1/rzEyQIKOh77j87n5bjWUNguXF8Y=";
@@ -578,7 +583,6 @@ lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3
static const char kSPKIHash_VeriSignUniversal[] =
"sha1/u8I+KQuzKHcdrT6iTb30I70GsD0=";
-// Not public
static const char kSPKIHash_Twitter1[] =
"sha1/Vv7zwhR9TtOIN/29MFI4cgHld40=";
@@ -733,25 +737,29 @@ static const char kSPKIHash_GeoTrustPrimary_G3[] =
#if 0
-----BEGIN CERTIFICATE-----
-MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u
-ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp
-bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV
-BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx
-NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3
-d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl
-MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u
-ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
-MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL
-Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr
-hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW
-nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi
-VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E
-BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ
-KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy
-T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf
-zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT
-J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e
-nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE=
+MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML
+RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp
+bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5
+IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3
+MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3
+LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp
+YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG
+A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq
+K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe
+sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX
+MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT
+XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/
+HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH
+4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
+HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub
+j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo
+U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf
+zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b
+u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+
+bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er
+fF6adulZkMV8gzURZVE=
-----END CERTIFICATE-----
#endif
static const char kSPKIHash_Entrust_2048[] =
@@ -1235,1162 +1243,23 @@ lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/
static const char kSPKIHash_GTECyberTrustGlobalRoot[] =
"sha1/WXkS3mF11m/EI7d3E3THlt5viHI=";
-#endif // NET_BASE_PUBLIC_KEY_HASHES_
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/base/transport_security_state.h"
-
-#if defined(USE_OPENSSL)
-#include <openssl/ecdsa.h>
-#include <openssl/ssl.h>
-#else // !defined(USE_OPENSSL)
-#include <cryptohi.h>
-#include <hasht.h>
-#include <keyhi.h>
-#include <pk11pub.h>
-#include <nspr.h>
-#endif
-
-#include <algorithm>
-#include <utility>
-
-#include "base/base64.h"
-#include "base/json/json_reader.h"
-#include "base/json/json_writer.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/metrics/histogram.h"
-#include "base/sha1.h"
-#include "base/string_number_conversions.h"
-#include "base/string_tokenizer.h"
-#include "base/string_util.h"
-#include "base/time.h"
-#include "base/utf_string_conversions.h"
-#include "base/values.h"
-#include "crypto/sha2.h"
-#include "googleurl/src/gurl.h"
-#include "net/base/asn1_util.h"
-#include "net/base/dns_util.h"
-#include "net/base/public_key_hashes.h"
-#include "net/base/ssl_info.h"
-#include "net/base/x509_certificate.h"
-#include "net/http/http_util.h"
-
-#if defined(USE_OPENSSL)
-#include "crypto/openssl_util.h"
-#endif
-
-namespace net {
-
-const long int TransportSecurityState::kMaxHSTSAgeSecs = 86400 * 365; // 1 year
-
-TransportSecurityState::TransportSecurityState(const std::string& hsts_hosts)
- : delegate_(NULL) {
- if (!hsts_hosts.empty()) {
- bool dirty;
- Deserialise(hsts_hosts, &dirty, &forced_hosts_);
- }
-}
-
-static std::string HashHost(const std::string& canonicalized_host) {
- char hashed[crypto::kSHA256Length];
- crypto::SHA256HashString(canonicalized_host, hashed, sizeof(hashed));
- return std::string(hashed, sizeof(hashed));
-}
-
-void TransportSecurityState::SetDelegate(
- TransportSecurityState::Delegate* delegate) {
- delegate_ = delegate;
-}
-
-void TransportSecurityState::EnableHost(const std::string& host,
- const DomainState& state) {
- DCHECK(CalledOnValidThread());
-
- const std::string canonicalized_host = CanonicalizeHost(host);
- if (canonicalized_host.empty())
- return;
-
- // Only override a preloaded state if the new state describes a more strict
- // policy. TODO(palmer): Reconsider this?
- DomainState existing_state;
- if (IsPreloadedSTS(canonicalized_host, true, &existing_state) &&
- canonicalized_host == CanonicalizeHost(existing_state.domain) &&
- existing_state.IsMoreStrict(state)) {
- return;
- }
-
- // Use the original creation date if we already have this host.
- DomainState state_copy(state);
- if (GetDomainState(&existing_state, host, true) &&
- !existing_state.created.is_null()) {
- state_copy.created = existing_state.created;
- }
-
- // We don't store these values.
- state_copy.preloaded = false;
- state_copy.domain.clear();
-
- enabled_hosts_[HashHost(canonicalized_host)] = state_copy;
- DirtyNotify();
-}
-
-bool TransportSecurityState::DeleteHost(const std::string& host) {
- DCHECK(CalledOnValidThread());
-
- const std::string canonicalized_host = CanonicalizeHost(host);
- if (canonicalized_host.empty())
- return false;
-
- std::map<std::string, DomainState>::iterator i = enabled_hosts_.find(
- HashHost(canonicalized_host));
- if (i != enabled_hosts_.end()) {
- enabled_hosts_.erase(i);
- DirtyNotify();
- return true;
- }
- return false;
-}
-
-bool TransportSecurityState::HasPinsForHost(DomainState* result,
- const std::string& host,
- bool sni_available) {
- DCHECK(CalledOnValidThread());
-
- return HasMetadata(result, host, sni_available) &&
- (!result->dynamic_spki_hashes.empty() ||
- !result->preloaded_spki_hashes.empty());
-}
-
-bool TransportSecurityState::GetDomainState(DomainState* result,
- const std::string& host,
- bool sni_available) {
- DCHECK(CalledOnValidThread());
-
- return HasMetadata(result, host, sni_available);
-}
-
-bool TransportSecurityState::HasMetadata(DomainState* result,
- const std::string& host,
- bool sni_available) {
- DCHECK(CalledOnValidThread());
-
- DomainState state;
- const std::string canonicalized_host = CanonicalizeHost(host);
- if (canonicalized_host.empty())
- return false;
-
- bool has_preload = IsPreloadedSTS(canonicalized_host, sni_available, &state);
- std::string canonicalized_preload = CanonicalizeHost(state.domain);
-
- base::Time current_time(base::Time::Now());
-
- for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
- std::string host_sub_chunk(&canonicalized_host[i],
- canonicalized_host.size() - i);
- // Exact match of a preload always wins.
- if (has_preload && host_sub_chunk == canonicalized_preload) {
- *result = state;
- return true;
- }
-
- std::map<std::string, DomainState>::iterator j =
- enabled_hosts_.find(HashHost(host_sub_chunk));
- if (j == enabled_hosts_.end())
- continue;
-
- if (current_time > j->second.expiry &&
- current_time > j->second.dynamic_spki_hashes_expiry) {
- enabled_hosts_.erase(j);
- DirtyNotify();
- continue;
- }
-
- state = j->second;
- state.domain = DNSDomainToString(host_sub_chunk);
-
- // Succeed if we matched the domain exactly or if subdomain matches are
- // allowed.
- if (i == 0 || j->second.include_subdomains) {
- *result = state;
- return true;
- }
-
- return false;
- }
-
- return false;
-}
-
-void TransportSecurityState::DeleteSince(const base::Time& time) {
- DCHECK(CalledOnValidThread());
-
- bool dirtied = false;
-
- std::map<std::string, DomainState>::iterator i = enabled_hosts_.begin();
- while (i != enabled_hosts_.end()) {
- if (i->second.created >= time) {
- dirtied = true;
- enabled_hosts_.erase(i++);
- } else {
- i++;
- }
- }
-
- if (dirtied)
- DirtyNotify();
-}
-
-// MaxAgeToInt converts a string representation of a number of seconds into a
-// int. We use strtol in order to handle overflow correctly. The string may
-// contain an arbitary number which we should truncate correctly rather than
-// throwing a parse failure.
-static bool MaxAgeToInt(std::string::const_iterator begin,
- std::string::const_iterator end,
- int* result) {
- const std::string s(begin, end);
- char* endptr;
- long int i = strtol(s.data(), &endptr, 10 /* base */);
- if (*endptr || i < 0)
- return false;
- if (i > TransportSecurityState::kMaxHSTSAgeSecs)
- i = TransportSecurityState::kMaxHSTSAgeSecs;
- *result = i;
- return true;
-}
-
-// Strip, Split, StringPair, and ParsePins are private implementation details
-// of ParsePinsHeader(std::string&, DomainState&).
-static std::string Strip(const std::string& source) {
- if (source.empty())
- return source;
-
- std::string::const_iterator start = source.begin();
- std::string::const_iterator end = source.end();
- HttpUtil::TrimLWS(&start, &end);
- return std::string(start, end);
-}
-
-typedef std::pair<std::string, std::string> StringPair;
-
-static StringPair Split(const std::string& source, char delimiter) {
- StringPair pair;
- size_t point = source.find(delimiter);
-
- pair.first = source.substr(0, point);
- if (std::string::npos != point)
- pair.second = source.substr(point + 1);
-
- return pair;
-}
-
-// TODO(palmer): Support both sha256 and sha1. This will require additional
-// infrastructure code changes and can come in a later patch.
-//
-// static
-bool TransportSecurityState::ParsePin(const std::string& value,
- SHA1Fingerprint* out) {
- StringPair slash = Split(Strip(value), '/');
- if (slash.first != "sha1")
- return false;
-
- std::string decoded;
- if (!base::Base64Decode(slash.second, &decoded) ||
- decoded.size() != arraysize(out->data)) {
- return false;
- }
-
- memcpy(out->data, decoded.data(), arraysize(out->data));
- return true;
-}
-
-static bool ParseAndAppendPin(const std::string& value,
- FingerprintVector* fingerprints) {
- // The base64'd fingerprint MUST be a quoted-string. 20 bytes base64'd is 28
- // characters; 32 bytes base64'd is 44 characters. TODO(palmer): Support
- // SHA256.
- size_t size = value.size();
- if (size != 30 || value[0] != '"' || value[size - 1] != '"')
- return false;
-
- std::string unquoted = HttpUtil::Unquote(value);
- std::string decoded;
- SHA1Fingerprint fp;
-
- if (!base::Base64Decode(unquoted, &decoded) ||
- decoded.size() != arraysize(fp.data)) {
- return false;
- }
-
- memcpy(fp.data, decoded.data(), arraysize(fp.data));
- fingerprints->push_back(fp);
- return true;
-}
-
-// static
-bool TransportSecurityState::GetPublicKeyHash(
- const X509Certificate& cert, SHA1Fingerprint* spki_hash) {
- std::string der_bytes;
- if (!X509Certificate::GetDEREncoded(cert.os_cert_handle(), &der_bytes))
- return false;
-
- base::StringPiece spki;
- if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki))
- return false;
-
- base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(spki.data()),
- spki.size(), spki_hash->data);
-
- return true;
-}
-
-struct FingerprintsEqualPredicate {
- explicit FingerprintsEqualPredicate(const SHA1Fingerprint& fingerprint) :
- fingerprint_(fingerprint) {}
-
- bool operator()(const SHA1Fingerprint& other) const {
- return fingerprint_.Equals(other);
- }
-
- const SHA1Fingerprint& fingerprint_;
-};
-
-// Returns true iff there is an item in |pins| which is not present in
-// |from_cert_chain|. Such an SPKI hash is called a "backup pin".
-static bool IsBackupPinPresent(const FingerprintVector& pins,
- const FingerprintVector& from_cert_chain) {
- for (FingerprintVector::const_iterator
- i = pins.begin(); i != pins.end(); ++i) {
- FingerprintVector::const_iterator j =
- std::find_if(from_cert_chain.begin(), from_cert_chain.end(),
- FingerprintsEqualPredicate(*i));
- if (j == from_cert_chain.end())
- return true;
- }
-
- return false;
-}
-
-static bool HashesIntersect(const FingerprintVector& a,
- const FingerprintVector& b) {
- for (FingerprintVector::const_iterator
- i = a.begin(); i != a.end(); ++i) {
- FingerprintVector::const_iterator j =
- std::find_if(b.begin(), b.end(), FingerprintsEqualPredicate(*i));
- if (j != b.end())
- return true;
- }
-
- return false;
-}
-
-// Returns true iff |pins| contains both a live and a backup pin. A live pin
-// is a pin whose SPKI is present in the certificate chain in |ssl_info|. A
-// backup pin is a pin intended for disaster recovery, not day-to-day use, and
-// thus must be absent from the certificate chain. The Public-Key-Pins header
-// specification requires both.
-static bool IsPinListValid(const FingerprintVector& pins,
- const SSLInfo& ssl_info) {
- if (pins.size() < 2)
- return false;
-
- const FingerprintVector& from_cert_chain = ssl_info.public_key_hashes;
- if (from_cert_chain.empty())
- return false;
-
- return IsBackupPinPresent(pins, from_cert_chain) &&
- HashesIntersect(pins, from_cert_chain);
-}
-
-// "Public-Key-Pins" ":"
-// "max-age" "=" delta-seconds ";"
-// "pin-" algo "=" base64 [ ";" ... ]
-//
-// static
-bool TransportSecurityState::ParsePinsHeader(const std::string& value,
- const SSLInfo& ssl_info,
- DomainState* state) {
- bool parsed_max_age = false;
- int max_age = 0;
- FingerprintVector pins;
-
- std::string source = value;
-
- while (!source.empty()) {
- StringPair semicolon = Split(source, ';');
- semicolon.first = Strip(semicolon.first);
- semicolon.second = Strip(semicolon.second);
- StringPair equals = Split(semicolon.first, '=');
- equals.first = Strip(equals.first);
- equals.second = Strip(equals.second);
-
- if (LowerCaseEqualsASCII(equals.first, "max-age")) {
- if (equals.second.empty() ||
- !MaxAgeToInt(equals.second.begin(), equals.second.end(), &max_age)) {
- return false;
- }
- if (max_age > kMaxHSTSAgeSecs)
- max_age = kMaxHSTSAgeSecs;
- parsed_max_age = true;
- } else if (LowerCaseEqualsASCII(equals.first, "pin-sha1")) {
- if (!ParseAndAppendPin(equals.second, &pins))
- return false;
- } else if (LowerCaseEqualsASCII(equals.first, "pin-sha256")) {
- // TODO(palmer)
- } else {
- // Silently ignore unknown directives for forward compatibility.
- }
-
- source = semicolon.second;
- }
-
- if (!parsed_max_age || !IsPinListValid(pins, ssl_info))
- return false;
-
- state->max_age = max_age;
- state->dynamic_spki_hashes_expiry =
- base::Time::Now() + base::TimeDelta::FromSeconds(max_age);
-
- state->dynamic_spki_hashes.clear();
- if (max_age > 0) {
- for (FingerprintVector::const_iterator i = pins.begin();
- i != pins.end(); i++) {
- state->dynamic_spki_hashes.push_back(*i);
- }
- }
-
- return true;
-}
-
-// "Strict-Transport-Security" ":"
-// "max-age" "=" delta-seconds [ ";" "includeSubDomains" ]
-//
-// static
-bool TransportSecurityState::ParseHeader(const std::string& value,
- int* max_age,
- bool* include_subdomains) {
- DCHECK(max_age);
- DCHECK(include_subdomains);
-
- int max_age_candidate = 0;
-
- enum ParserState {
- START,
- AFTER_MAX_AGE_LABEL,
- AFTER_MAX_AGE_EQUALS,
- AFTER_MAX_AGE,
- AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER,
- AFTER_INCLUDE_SUBDOMAINS,
- } state = START;
-
- StringTokenizer tokenizer(value, " \t=;");
- tokenizer.set_options(StringTokenizer::RETURN_DELIMS);
- while (tokenizer.GetNext()) {
- DCHECK(!tokenizer.token_is_delim() || tokenizer.token().length() == 1);
- switch (state) {
- case START:
- if (IsAsciiWhitespace(*tokenizer.token_begin()))
- continue;
- if (!LowerCaseEqualsASCII(tokenizer.token(), "max-age"))
- return false;
- state = AFTER_MAX_AGE_LABEL;
- break;
-
- case AFTER_MAX_AGE_LABEL:
- if (IsAsciiWhitespace(*tokenizer.token_begin()))
- continue;
- if (*tokenizer.token_begin() != '=')
- return false;
- DCHECK_EQ(tokenizer.token().length(), 1U);
- state = AFTER_MAX_AGE_EQUALS;
- break;
-
- case AFTER_MAX_AGE_EQUALS:
- if (IsAsciiWhitespace(*tokenizer.token_begin()))
- continue;
- if (!MaxAgeToInt(tokenizer.token_begin(),
- tokenizer.token_end(),
- &max_age_candidate))
- return false;
- state = AFTER_MAX_AGE;
- break;
-
- case AFTER_MAX_AGE:
- if (IsAsciiWhitespace(*tokenizer.token_begin()))
- continue;
- if (*tokenizer.token_begin() != ';')
- return false;
- state = AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER;
- break;
-
- case AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER:
- if (IsAsciiWhitespace(*tokenizer.token_begin()))
- continue;
- if (!LowerCaseEqualsASCII(tokenizer.token(), "includesubdomains"))
- return false;
- state = AFTER_INCLUDE_SUBDOMAINS;
- break;
-
- case AFTER_INCLUDE_SUBDOMAINS:
- if (!IsAsciiWhitespace(*tokenizer.token_begin()))
- return false;
- break;
-
- default:
- NOTREACHED();
- }
- }
-
- // We've consumed all the input. Let's see what state we ended up in.
- switch (state) {
- case START:
- case AFTER_MAX_AGE_LABEL:
- case AFTER_MAX_AGE_EQUALS:
- return false;
- case AFTER_MAX_AGE:
- *max_age = max_age_candidate;
- *include_subdomains = false;
- return true;
- case AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER:
- return false;
- case AFTER_INCLUDE_SUBDOMAINS:
- *max_age = max_age_candidate;
- *include_subdomains = true;
- return true;
- default:
- NOTREACHED();
- return false;
- }
-}
-
-// Side pinning and superfluous certificates:
-//
-// In SSLClientSocketNSS::DoVerifyCertComplete we look for certificates with a
-// Subject of CN=meta. When we find one we'll currently try and parse side
-// pinned key from it.
-//
-// A side pin is a key which can be pinned to, but also can be kept offline and
-// still held by the site owner. The CN=meta certificate is just a backwards
-// compatiable method of carrying a lump of bytes to the client. (We could use
-// a TLS extension just as well, but it's a lot easier for admins to add extra
-// certificates to the chain.)
-
-// A TagMap represents the simple key-value structure that we use. Keys are
-// 32-bit ints. Values are byte strings.
-typedef std::map<uint32, base::StringPiece> TagMap;
-
-// ParseTags parses a list of key-value pairs from |in| to |out| and advances
-// |in| past the data. The key-value pair data is:
-// u16le num_tags
-// u32le tag[num_tags]
-// u16le lengths[num_tags]
-// ...data...
-static bool ParseTags(base::StringPiece* in, TagMap *out) {
- // Many part of Chrome already assume little-endian. This is just to help
- // anyone who should try to port it in the future.
-#if defined(__BYTE_ORDER)
- // Linux check
- COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN, assumes_little_endian);
-#elif defined(__BIG_ENDIAN__)
- // Mac check
- #error assumes little endian
-#endif
-
- uint16 num_tags_16;
- if (in->size() < sizeof(num_tags_16))
- return false;
-
- memcpy(&num_tags_16, in->data(), sizeof(num_tags_16));
- in->remove_prefix(sizeof(num_tags_16));
- unsigned num_tags = num_tags_16;
-
- if (in->size() < 6 * num_tags)
- return false;
-
- const uint32* tags = reinterpret_cast<const uint32*>(in->data());
- const uint16* lens = reinterpret_cast<const uint16*>(
- in->data() + 4*num_tags);
- in->remove_prefix(6*num_tags);
-
- uint32 prev_tag = 0;
- for (unsigned i = 0; i < num_tags; i++) {
- size_t len = lens[i];
- uint32 tag = tags[i];
-
- if (in->size() < len)
- return false;
- // tags must be in ascending order.
- if (i > 0 && prev_tag >= tag)
- return false;
- (*out)[tag] = base::StringPiece(in->data(), len);
- in->remove_prefix(len);
- prev_tag = tag;
- }
-
- return true;
-}
-
-// GetTag extracts the data associated with |tag| in |tags|.
-static bool GetTag(uint32 tag, const TagMap& tags, base::StringPiece* out) {
- TagMap::const_iterator i = tags.find(tag);
- if (i == tags.end())
- return false;
-
- *out = i->second;
- return true;
-}
-
-// kP256SubjectPublicKeyInfoPrefix can be prepended onto a P256 elliptic curve
-// point in X9.62 format in order to make a valid SubjectPublicKeyInfo. The
-// ASN.1 interpretation of these bytes is:
-//
-// 0:d=0 hl=2 l= 89 cons: SEQUENCE
-// 2:d=1 hl=2 l= 19 cons: SEQUENCE
-// 4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey
-// 13:d=2 hl=2 l= 8 prim: OBJECT :prime256v1
-// 23:d=1 hl=2 l= 66 prim: BIT STRING
-static const uint8 kP256SubjectPublicKeyInfoPrefix[] = {
- 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
- 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
- 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
- 0x42, 0x00,
-};
-
-// VerifySignature returns true iff |sig| is a valid signature of
-// |hash| by |pubkey|. The actual implementation is crypto library
-// specific.
-static bool VerifySignature(const base::StringPiece& pubkey,
- const base::StringPiece& sig,
- const base::StringPiece& hash);
-
-#if defined(USE_OPENSSL)
-
-static EVP_PKEY* DecodeX962P256PublicKey(
- const base::StringPiece& pubkey_bytes) {
- // The public key is an X9.62 encoded P256 point.
- if (pubkey_bytes.size() != 1 + 2*32)
- return NULL;
-
- std::string pubkey_spki(
- reinterpret_cast<const char*>(kP256SubjectPublicKeyInfoPrefix),
- sizeof(kP256SubjectPublicKeyInfoPrefix));
- pubkey_spki += pubkey_bytes.as_string();
-
- EVP_PKEY* ret = NULL;
- const unsigned char* der_pubkey =
- reinterpret_cast<const unsigned char*>(pubkey_spki.data());
- d2i_PUBKEY(&ret, &der_pubkey, pubkey_spki.size());
- return ret;
-}
-
-static bool VerifySignature(const base::StringPiece& pubkey,
- const base::StringPiece& sig,
- const base::StringPiece& hash) {
- crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> secpubkey(
- DecodeX962P256PublicKey(pubkey));
- if (!secpubkey.get())
- return false;
-
-
- crypto::ScopedOpenSSL<EC_KEY, EC_KEY_free> ec_key(
- EVP_PKEY_get1_EC_KEY(secpubkey.get()));
- if (!ec_key.get())
- return false;
-
- return ECDSA_verify(0, reinterpret_cast<const unsigned char*>(hash.data()),
- hash.size(),
- reinterpret_cast<const unsigned char*>(sig.data()),
- sig.size(), ec_key.get()) == 1;
-}
-
-#else
-
-// DecodeX962P256PublicKey parses an uncompressed, X9.62 format, P256 elliptic
-// curve point from |pubkey_bytes| and returns it as a SECKEYPublicKey.
-static SECKEYPublicKey* DecodeX962P256PublicKey(
- const base::StringPiece& pubkey_bytes) {
- // The public key is an X9.62 encoded P256 point.
- if (pubkey_bytes.size() != 1 + 2*32)
- return NULL;
-
- std::string pubkey_spki(
- reinterpret_cast<const char*>(kP256SubjectPublicKeyInfoPrefix),
- sizeof(kP256SubjectPublicKeyInfoPrefix));
- pubkey_spki += pubkey_bytes.as_string();
-
- SECItem der;
- memset(&der, 0, sizeof(der));
- der.data = reinterpret_cast<uint8*>(const_cast<char*>(pubkey_spki.data()));
- der.len = pubkey_spki.size();
-
- CERTSubjectPublicKeyInfo* spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&der);
- if (!spki)
- return NULL;
- SECKEYPublicKey* public_key = SECKEY_ExtractPublicKey(spki);
- SECKEY_DestroySubjectPublicKeyInfo(spki);
-
- return public_key;
-}
-
-static bool VerifySignature(const base::StringPiece& pubkey,
- const base::StringPiece& sig,
- const base::StringPiece& hash) {
- SECKEYPublicKey* secpubkey = DecodeX962P256PublicKey(pubkey);
- if (!secpubkey)
- return false;
-
- SECItem sigitem;
- memset(&sigitem, 0, sizeof(sigitem));
- sigitem.data = reinterpret_cast<uint8*>(const_cast<char*>(sig.data()));
- sigitem.len = sig.size();
-
- // |decoded_sigitem| is newly allocated, as is the data that it points to.
- SECItem* decoded_sigitem = DSAU_DecodeDerSigToLen(
- &sigitem, SECKEY_SignatureLen(secpubkey));
-
- if (!decoded_sigitem) {
- SECKEY_DestroyPublicKey(secpubkey);
- return false;
- }
-
- SECItem hashitem;
- memset(&hashitem, 0, sizeof(hashitem));
- hashitem.data = reinterpret_cast<unsigned char*>(
- const_cast<char*>(hash.data()));
- hashitem.len = hash.size();
-
- SECStatus rv = PK11_Verify(secpubkey, decoded_sigitem, &hashitem, NULL);
- SECKEY_DestroyPublicKey(secpubkey);
- SECITEM_FreeItem(decoded_sigitem, PR_TRUE);
- return rv == SECSuccess;
-}
-
-#endif // !defined(USE_OPENSSL)
-
-// These are the tag values that we use. Tags are little-endian on the wire and
-// these values correspond to the ASCII of the name.
-static const uint32 kTagALGO = 0x4f474c41;
-static const uint32 kTagP256 = 0x36353250;
-static const uint32 kTagPUBK = 0x4b425550;
-static const uint32 kTagSIG = 0x474953;
-static const uint32 kTagSPIN = 0x4e495053;
-
-// static
-bool TransportSecurityState::ParseSidePin(
- const base::StringPiece& leaf_spki,
- const base::StringPiece& in_side_info,
- FingerprintVector* out_pub_key_hash) {
- base::StringPiece side_info(in_side_info);
-
- TagMap outer;
- if (!ParseTags(&side_info, &outer))
- return false;
- // trailing data is not allowed
- if (side_info.size())
- return false;
-
- base::StringPiece side_pin_bytes;
- if (!GetTag(kTagSPIN, outer, &side_pin_bytes))
- return false;
-
- bool have_parsed_a_key = false;
- uint8 leaf_spki_hash[crypto::kSHA256Length];
- bool have_leaf_spki_hash = false;
-
- while (side_pin_bytes.size() > 0) {
- TagMap side_pin;
- if (!ParseTags(&side_pin_bytes, &side_pin))
- return false;
-
- base::StringPiece algo, pubkey, sig;
- if (!GetTag(kTagALGO, side_pin, &algo) ||
- !GetTag(kTagPUBK, side_pin, &pubkey) ||
- !GetTag(kTagSIG, side_pin, &sig)) {
- return false;
- }
-
- if (algo.size() != sizeof(kTagP256) ||
- 0 != memcmp(algo.data(), &kTagP256, sizeof(kTagP256))) {
- // We don't support anything but P256 at the moment.
- continue;
- }
-
- if (!have_leaf_spki_hash) {
- crypto::SHA256HashString(
- leaf_spki.as_string(), leaf_spki_hash, sizeof(leaf_spki_hash));
- have_leaf_spki_hash = true;
- }
-
- if (VerifySignature(pubkey, sig, base::StringPiece(
- reinterpret_cast<const char*>(leaf_spki_hash),
- sizeof(leaf_spki_hash)))) {
- SHA1Fingerprint fpr;
- base::SHA1HashBytes(
- reinterpret_cast<const uint8*>(pubkey.data()),
- pubkey.size(),
- fpr.data);
- out_pub_key_hash->push_back(fpr);
- have_parsed_a_key = true;
- }
- }
-
- return have_parsed_a_key;
-}
-
-// This function converts the binary hashes, which we store in
-// |enabled_hosts_|, to a base64 string which we can include in a JSON file.
-static std::string HashedDomainToExternalString(const std::string& hashed) {
- std::string out;
- CHECK(base::Base64Encode(hashed, &out));
- return out;
-}
-
-// This inverts |HashedDomainToExternalString|, above. It turns an external
-// string (from a JSON file) into an internal (binary) string.
-static std::string ExternalStringToHashedDomain(const std::string& external) {
- std::string out;
- if (!base::Base64Decode(external, &out) ||
- out.size() != crypto::kSHA256Length) {
- return std::string();
- }
-
- return out;
-}
-
-static ListValue* SPKIHashesToListValue(const FingerprintVector& hashes) {
- ListValue* pins = new ListValue;
-
- for (FingerprintVector::const_iterator i = hashes.begin();
- i != hashes.end(); ++i) {
- std::string hash_str(reinterpret_cast<const char*>(i->data),
- sizeof(i->data));
- std::string b64;
- base::Base64Encode(hash_str, &b64);
- pins->Append(new StringValue("sha1/" + b64));
- }
-
- return pins;
-}
-
-bool TransportSecurityState::Serialise(std::string* output) {
- DCHECK(CalledOnValidThread());
-
- DictionaryValue toplevel;
- base::Time now = base::Time::Now();
- for (std::map<std::string, DomainState>::const_iterator
- i = enabled_hosts_.begin(); i != enabled_hosts_.end(); ++i) {
- DictionaryValue* state = new DictionaryValue;
- state->SetBoolean("include_subdomains", i->second.include_subdomains);
- state->SetDouble("created", i->second.created.ToDoubleT());
- state->SetDouble("expiry", i->second.expiry.ToDoubleT());
- state->SetDouble("dynamic_spki_hashes_expiry",
- i->second.dynamic_spki_hashes_expiry.ToDoubleT());
-
- switch (i->second.mode) {
- case DomainState::MODE_STRICT:
- state->SetString("mode", "strict");
- break;
- case DomainState::MODE_SPDY_ONLY:
- state->SetString("mode", "spdy-only");
- break;
- case DomainState::MODE_PINNING_ONLY:
- state->SetString("mode", "pinning-only");
- break;
- default:
- NOTREACHED() << "DomainState with unknown mode";
- delete state;
- continue;
- }
-
- state->Set("preloaded_spki_hashes",
- SPKIHashesToListValue(i->second.preloaded_spki_hashes));
-
- if (now < i->second.dynamic_spki_hashes_expiry) {
- state->Set("dynamic_spki_hashes",
- SPKIHashesToListValue(i->second.dynamic_spki_hashes));
- }
-
- toplevel.Set(HashedDomainToExternalString(i->first), state);
- }
-
- base::JSONWriter::WriteWithOptions(&toplevel,
- base::JSONWriter::OPTIONS_PRETTY_PRINT,
- output);
- return true;
-}
-
-bool TransportSecurityState::LoadEntries(const std::string& input,
- bool* dirty) {
- DCHECK(CalledOnValidThread());
-
- enabled_hosts_.clear();
- return Deserialise(input, dirty, &enabled_hosts_);
-}
-
-static bool AddHash(const std::string& type_and_base64,
- FingerprintVector* out) {
- SHA1Fingerprint hash;
-
- if (!TransportSecurityState::ParsePin(type_and_base64, &hash))
- return false;
-
- out->push_back(hash);
- return true;
-}
-
-static void SPKIHashesFromListValue(FingerprintVector* hashes,
- const ListValue& pins) {
- size_t num_pins = pins.GetSize();
- for (size_t i = 0; i < num_pins; ++i) {
- std::string type_and_base64;
- if (pins.GetString(i, &type_and_base64))
- AddHash(type_and_base64, hashes);
- }
-}
-
-// static
-bool TransportSecurityState::Deserialise(
- const std::string& input,
- bool* dirty,
- std::map<std::string, DomainState>* out) {
- scoped_ptr<Value> value(
- base::JSONReader::Read(input, false /* do not allow trailing commas */));
- if (!value.get() || !value->IsType(Value::TYPE_DICTIONARY))
- return false;
-
- DictionaryValue* dict_value = reinterpret_cast<DictionaryValue*>(value.get());
- const base::Time current_time(base::Time::Now());
- bool dirtied = false;
-
- for (DictionaryValue::key_iterator i = dict_value->begin_keys();
- i != dict_value->end_keys(); ++i) {
- DictionaryValue* state;
- if (!dict_value->GetDictionaryWithoutPathExpansion(*i, &state))
- continue;
-
- bool include_subdomains;
- std::string mode_string;
- double created;
- double expiry;
- double dynamic_spki_hashes_expiry = 0.0;
-
- if (!state->GetBoolean("include_subdomains", &include_subdomains) ||
- !state->GetString("mode", &mode_string) ||
- !state->GetDouble("expiry", &expiry)) {
- continue;
- }
-
- // Don't fail if this key is not present.
- (void) state->GetDouble("dynamic_spki_hashes_expiry",
- &dynamic_spki_hashes_expiry);
-
- ListValue* pins_list = NULL;
- FingerprintVector preloaded_spki_hashes;
- if (state->GetList("preloaded_spki_hashes", &pins_list))
- SPKIHashesFromListValue(&preloaded_spki_hashes, *pins_list);
-
- FingerprintVector dynamic_spki_hashes;
- if (state->GetList("dynamic_spki_hashes", &pins_list))
- SPKIHashesFromListValue(&dynamic_spki_hashes, *pins_list);
-
- DomainState::Mode mode;
- if (mode_string == "strict") {
- mode = DomainState::MODE_STRICT;
- } else if (mode_string == "spdy-only") {
- mode = DomainState::MODE_SPDY_ONLY;
- } else if (mode_string == "pinning-only") {
- mode = DomainState::MODE_PINNING_ONLY;
- } else {
- LOG(WARNING) << "Unknown TransportSecurityState mode string found: "
- << mode_string;
- continue;
- }
-
- base::Time expiry_time = base::Time::FromDoubleT(expiry);
- base::Time dynamic_spki_hashes_expiry_time =
- base::Time::FromDoubleT(dynamic_spki_hashes_expiry);
- base::Time created_time;
- if (state->GetDouble("created", &created)) {
- created_time = base::Time::FromDoubleT(created);
- } else {
- // We're migrating an old entry with no creation date. Make sure we
- // write the new date back in a reasonable time frame.
- dirtied = true;
- created_time = base::Time::Now();
- }
-
- if (expiry_time <= current_time &&
- dynamic_spki_hashes_expiry_time <= current_time) {
- // Make sure we dirty the state if we drop an entry.
- dirtied = true;
- continue;
- }
-
- std::string hashed = ExternalStringToHashedDomain(*i);
- if (hashed.empty()) {
- dirtied = true;
- continue;
- }
-
- DomainState new_state;
- new_state.mode = mode;
- new_state.created = created_time;
- new_state.expiry = expiry_time;
- new_state.include_subdomains = include_subdomains;
- new_state.preloaded_spki_hashes = preloaded_spki_hashes;
- new_state.dynamic_spki_hashes = dynamic_spki_hashes;
- new_state.dynamic_spki_hashes_expiry = dynamic_spki_hashes_expiry_time;
- (*out)[hashed] = new_state;
- }
-
- *dirty = dirtied;
- return true;
-}
-
-TransportSecurityState::~TransportSecurityState() {
-}
-
-void TransportSecurityState::DirtyNotify() {
- DCHECK(CalledOnValidThread());
-
- if (delegate_)
- delegate_->StateIsDirty(this);
-}
-
-// static
-std::string TransportSecurityState::CanonicalizeHost(const std::string& host) {
- // We cannot perform the operations as detailed in the spec here as |host|
- // has already undergone IDN processing before it reached us. Thus, we check
- // that there are no invalid characters in the host and lowercase the result.
-
- std::string new_host;
- if (!DNSDomainFromDot(host, &new_host)) {
- // DNSDomainFromDot can fail if any label is > 63 bytes or if the whole
- // name is >255 bytes. However, search terms can have those properties.
- return std::string();
- }
-
- for (size_t i = 0; new_host[i]; i += new_host[i] + 1) {
- const unsigned label_length = static_cast<unsigned>(new_host[i]);
- if (!label_length)
- break;
-
- for (size_t j = 0; j < label_length; ++j) {
- // RFC 3490, 4.1, step 3
- if (!IsSTD3ASCIIValidCharacter(new_host[i + 1 + j]))
- return std::string();
-
- new_host[i + 1 + j] = tolower(new_host[i + 1 + j]);
- }
-
- // step 3(b)
- if (new_host[i + 1] == '-' ||
- new_host[i + label_length] == '-') {
- return std::string();
- }
- }
-
- return new_host;
-}
-
-// |ReportUMAOnPinFailure| uses these to report which domain was associated
-// with the public key pinning failure.
-//
-// DO NOT CHANGE THE ORDERING OF THESE NAMES OR REMOVE ANY OF THEM. Add new
-// domains at the END of the listing (but before DOMAIN_NUM_EVENTS).
-enum SecondLevelDomainName {
- DOMAIN_NOT_PINNED,
-
- DOMAIN_GOOGLE_COM,
- DOMAIN_ANDROID_COM,
- DOMAIN_GOOGLE_ANALYTICS_COM,
- DOMAIN_GOOGLEPLEX_COM,
- DOMAIN_YTIMG_COM,
- DOMAIN_GOOGLEUSERCONTENT_COM,
- DOMAIN_YOUTUBE_COM,
- DOMAIN_GOOGLEAPIS_COM,
- DOMAIN_GOOGLEADSERVICES_COM,
- DOMAIN_GOOGLECODE_COM,
- DOMAIN_APPSPOT_COM,
- DOMAIN_GOOGLESYNDICATION_COM,
- DOMAIN_DOUBLECLICK_NET,
- DOMAIN_GSTATIC_COM,
- DOMAIN_GMAIL_COM,
- DOMAIN_GOOGLEMAIL_COM,
- DOMAIN_GOOGLEGROUPS_COM,
-
- DOMAIN_TORPROJECT_ORG,
-
- DOMAIN_TWITTER_COM,
- DOMAIN_TWIMG_COM,
-
- DOMAIN_AKAMAIHD_NET,
-
- // Boundary value for UMA_HISTOGRAM_ENUMERATION:
- DOMAIN_NUM_EVENTS
-};
-
-// PublicKeyPins contains a number of SubjectPublicKeyInfo hashes for a site.
-// The validated certificate chain for the site must not include any of
-// |excluded_hashes| and must include one or more of |required_hashes|.
-struct PublicKeyPins {
- const char* const* required_hashes;
- const char* const* excluded_hashes;
-};
-
-struct HSTSPreload {
- uint8 length;
- bool include_subdomains;
- char dns_name[30];
- bool https_required;
- PublicKeyPins pins;
- SecondLevelDomainName second_level_domain_name;
-};
-
-static bool HasPreload(const struct HSTSPreload* entries, size_t num_entries,
- const std::string& canonicalized_host, size_t i,
- TransportSecurityState::DomainState* out, bool* ret) {
- for (size_t j = 0; j < num_entries; j++) {
- if (entries[j].length == canonicalized_host.size() - i &&
- memcmp(entries[j].dns_name, &canonicalized_host[i],
- entries[j].length) == 0) {
- if (!entries[j].include_subdomains && i != 0) {
- *ret = false;
- } else {
- out->include_subdomains = entries[j].include_subdomains;
- *ret = true;
- if (!entries[j].https_required)
- out->mode = TransportSecurityState::DomainState::MODE_PINNING_ONLY;
- if (entries[j].pins.required_hashes) {
- const char* const* hash = entries[j].pins.required_hashes;
- while (*hash) {
- bool ok = AddHash(*hash, &out->preloaded_spki_hashes);
- DCHECK(ok) << " failed to parse " << *hash;
- hash++;
- }
- }
- if (entries[j].pins.excluded_hashes) {
- const char* const* hash = entries[j].pins.excluded_hashes;
- while (*hash) {
- bool ok = AddHash(*hash, &out->bad_preloaded_spki_hashes);
- DCHECK(ok) << " failed to parse " << *hash;
- hash++;
- }
- }
- }
- return true;
- }
- }
- return false;
-}
+// The following is static data describing the hosts that are hardcoded with
+// certificate pins or HSTS information.
// kNoRejectedPublicKeys is a placeholder for when no public keys are rejected.
static const char* const kNoRejectedPublicKeys[] = {
NULL,
};
+static const char* const kTestAcceptableCerts[] = {
+ kSPKIHash_TestSPKI,
+ NULL,
+};
+#define kTestPins { \
+ kTestAcceptableCerts, \
+ kNoRejectedPublicKeys, \
+}
+
static const char* const kGoogleAcceptableCerts[] = {
kSPKIHash_VeriSignClass3,
kSPKIHash_VeriSignClass3_G3,
@@ -2451,8 +1320,6 @@ static const char* const kTwitterComAcceptableCerts[] = {
kNoRejectedPublicKeys, \
}
-// kTwitterCDNAcceptableCerts are the set of public keys valid for Twitter's
-// CDNs, which includes all the keys from kTwitterComAcceptableCerts.
static const char* const kTwitterCDNAcceptableCerts[] = {
kSPKIHash_VeriSignClass1,
kSPKIHash_VeriSignClass3,
@@ -2473,7 +1340,6 @@ static const char* const kTwitterCDNAcceptableCerts[] = {
kSPKIHash_GeoTrustPrimary_G2,
kSPKIHash_GeoTrustPrimary_G3,
kSPKIHash_Twitter1,
-
kSPKIHash_Entrust_2048,
kSPKIHash_Entrust_EV,
kSPKIHash_Entrust_G2,
@@ -2498,35 +1364,14 @@ static const char* const kTwitterCDNAcceptableCerts[] = {
kNoRejectedPublicKeys, \
}
-// kTestAcceptableCerts doesn't actually match any public keys and is used
-// with "pinningtest.appspot.com", below, to test if pinning is active.
-static const char* const kTestAcceptableCerts[] = {
- "sha1/AAAAAAAAAAAAAAAAAAAAAAAAAAA=",
- NULL,
-};
-#define kTestPins { \
- kTestAcceptableCerts, \
- kNoRejectedPublicKeys, \
-}
-
-#define kNoPins { \
+#define kNoPins {\
NULL, NULL, \
}
-#if defined(OS_CHROMEOS)
- static const bool kTwitterHSTS = true;
-#else
- static const bool kTwitterHSTS = false;
-#endif
-
-// In the medium term this list is likely to just be hardcoded here. This
-// slightly odd form removes the need for additional relocations records.
static const struct HSTSPreload kPreloadedSTS[] = {
- // (*.)google.com, iff using SSL must use an acceptable certificate.
- {12, true, "\006google\003com", false, kGooglePins, DOMAIN_GOOGLE_COM },
{25, true, "\013pinningtest\007appspot\003com", false, kTestPins, DOMAIN_APPSPOT_COM },
- // Now we force HTTPS for subtrees of google.com.
- {19, true, "\006health\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
+ {12, true, "\006google\003com", false, kGooglePins, DOMAIN_GOOGLE_COM },
+ {19, true, "\006health\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
{21, true, "\010checkout\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
{19, true, "\006chrome\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
{17, true, "\004docs\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
@@ -2541,20 +1386,13 @@ static const struct HSTSPreload kPreloadedSTS[] = {
{17, true, "\004talk\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
{29, true, "\020hostedtalkgadget\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
{17, true, "\004plus\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
- // Other Google-related domains that must use HTTPS.
{20, true, "\006market\007android\003com", true, kGooglePins, DOMAIN_ANDROID_COM },
{26, true, "\003ssl\020google-analytics\003com", true, kGooglePins, DOMAIN_GOOGLE_ANALYTICS_COM },
{18, true, "\005drive\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
{16, true, "\012googleplex\003com", true, kGooglePins, DOMAIN_GOOGLEPLEX_COM },
{19, true, "\006groups\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
{17, true, "\004apis\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
- // chart.apis.google.com is *not* HSTS because the certificate doesn't match
- // and there are lots of links out there that still use the name. The correct
- // hostname for this is chart.googleapis.com.
- {23, true, "\005chart\004apis\006google\003com", false, kGooglePins, DOMAIN_GOOGLE_COM},
-
- // Other Google-related domains that must use an acceptable certificate
- // iff using SSL.
+ {23, true, "\005chart\004apis\006google\003com", false, kGooglePins, DOMAIN_GOOGLE_COM },
{11, true, "\005ytimg\003com", false, kGooglePins, DOMAIN_YTIMG_COM },
{23, true, "\021googleusercontent\003com", false, kGooglePins, DOMAIN_GOOGLEUSERCONTENT_COM },
{13, true, "\007youtube\003com", false, kGooglePins, DOMAIN_YOUTUBE_COM },
@@ -2565,14 +1403,11 @@ static const struct HSTSPreload kPreloadedSTS[] = {
{23, true, "\021googlesyndication\003com", false, kGooglePins, DOMAIN_GOOGLESYNDICATION_COM },
{17, true, "\013doubleclick\003net", false, kGooglePins, DOMAIN_DOUBLECLICK_NET },
{17, true, "\003ssl\007gstatic\003com", false, kGooglePins, DOMAIN_GSTATIC_COM },
- // Exclude the learn.doubleclick.net subdomain because it uses a different
- // CA.
{23, true, "\005learn\013doubleclick\003net", false, kNoPins, DOMAIN_NOT_PINNED },
- // Now we force HTTPS for other sites that have requested it.
{16, false, "\003www\006paypal\003com", true, kNoPins, DOMAIN_NOT_PINNED },
{16, false, "\003www\006elanex\003biz", true, kNoPins, DOMAIN_NOT_PINNED },
- {12, true, "\006jottit\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {19, true, "\015sunshinepress\003org", true, kNoPins, DOMAIN_NOT_PINNED },
+ {12, true, "\006jottit\003com", true, kNoPins, DOMAIN_NOT_PINNED },
+ {19, true, "\015sunshinepress\003org", true, kNoPins, DOMAIN_NOT_PINNED },
{21, false, "\003www\013noisebridge\003net", true, kNoPins, DOMAIN_NOT_PINNED },
{10, false, "\004neg9\003org", true, kNoPins, DOMAIN_NOT_PINNED },
{12, true, "\006riseup\003net", true, kNoPins, DOMAIN_NOT_PINNED },
@@ -2625,23 +1460,22 @@ static const struct HSTSPreload kPreloadedSTS[] = {
{12, true, "\006ubertt\003org", true, kNoPins, DOMAIN_NOT_PINNED },
{9, true, "\004pixi\002me", true, kNoPins, DOMAIN_NOT_PINNED },
{14, true, "\010grepular\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {16, false , "\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {20, false , "\003www\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {26, false , "\011developer\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {30, false , "\003www\011developer\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {24, false , "\007sandbox\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED },
- {28, false , "\003www\007sandbox\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED },
+ {16, false, "\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED },
+ {20, false, "\003www\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED },
+ {26, false, "\011developer\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED },
+ {30, false, "\003www\011developer\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED },
+ {24, false, "\007sandbox\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED },
+ {28, false, "\003www\007sandbox\012mydigipass\003com", true, kNoPins, DOMAIN_NOT_PINNED },
{12, true, "\006crypto\003cat", true, kNoPins, DOMAIN_NOT_PINNED },
{25, true, "\014bigshinylock\006minazo\003net", true, kNoPins, DOMAIN_NOT_PINNED },
{10, true, "\005crate\002io", true, kNoPins, DOMAIN_NOT_PINNED },
-
- {13, false, "\007twitter\003com", kTwitterHSTS, kTwitterComPins, DOMAIN_TWITTER_COM },
- {17, true, "\003www\007twitter\003com", kTwitterHSTS, kTwitterComPins, DOMAIN_TWITTER_COM },
- {17, true, "\003api\007twitter\003com", kTwitterHSTS, kTwitterCDNPins, DOMAIN_TWITTER_COM },
- {19, true, "\005oauth\007twitter\003com", kTwitterHSTS, kTwitterComPins, DOMAIN_TWITTER_COM },
- {20, true, "\006mobile\007twitter\003com", kTwitterHSTS, kTwitterComPins, DOMAIN_TWITTER_COM },
- {17, true, "\003dev\007twitter\003com", kTwitterHSTS, kTwitterComPins, DOMAIN_TWITTER_COM },
- {22, true, "\010business\007twitter\003com", kTwitterHSTS, kTwitterComPins, DOMAIN_TWITTER_COM },
+ {13, false, "\007twitter\003com", false, kTwitterComPins, DOMAIN_TWITTER_COM },
+ {17, true, "\003www\007twitter\003com", false, kTwitterComPins, DOMAIN_TWITTER_COM },
+ {17, true, "\003api\007twitter\003com", false, kTwitterCDNPins, DOMAIN_TWITTER_COM },
+ {19, true, "\005oauth\007twitter\003com", false, kTwitterComPins, DOMAIN_TWITTER_COM },
+ {20, true, "\006mobile\007twitter\003com", false, kTwitterComPins, DOMAIN_TWITTER_COM },
+ {17, true, "\003dev\007twitter\003com", false, kTwitterComPins, DOMAIN_TWITTER_COM },
+ {22, true, "\010business\007twitter\003com", false, kTwitterComPins, DOMAIN_TWITTER_COM },
{22, true, "\010platform\007twitter\003com", false, kTwitterCDNPins, DOMAIN_TWITTER_COM },
{15, true, "\003si0\005twimg\003com", false, kTwitterCDNPins, DOMAIN_TWIMG_COM },
{23, true, "\010twimg0-a\010akamaihd\003net", false, kTwitterCDNPins, DOMAIN_AKAMAIHD_NET },
@@ -2649,188 +1483,13 @@ static const struct HSTSPreload kPreloadedSTS[] = {
static const size_t kNumPreloadedSTS = ARRAYSIZE_UNSAFE(kPreloadedSTS);
static const struct HSTSPreload kPreloadedSNISTS[] = {
- // These SNI-only domains must always use HTTPS.
{11, false, "\005gmail\003com", true, kGooglePins, DOMAIN_GMAIL_COM },
{16, false, "\012googlemail\003com", true, kGooglePins, DOMAIN_GOOGLEMAIL_COM },
{15, false, "\003www\005gmail\003com", true, kGooglePins, DOMAIN_GMAIL_COM },
{20, false, "\003www\012googlemail\003com", true, kGooglePins, DOMAIN_GOOGLEMAIL_COM },
- // These SNI-only domains must use an acceptable certificate iff using
- // HTTPS.
{22, true, "\020google-analytics\003com", false, kGooglePins, DOMAIN_GOOGLE_ANALYTICS_COM },
- // www. requires SNI.
{18, true, "\014googlegroups\003com", false, kGooglePins, DOMAIN_GOOGLEGROUPS_COM },
};
static const size_t kNumPreloadedSNISTS = ARRAYSIZE_UNSAFE(kPreloadedSNISTS);
-// Returns the HSTSPreload entry for the |canonicalized_host| in |entries|,
-// or NULL if there is none. Prefers exact hostname matches to those that
-// match only because HSTSPreload.include_subdomains is true.
-//
-// |canonicalized_host| should be the hostname as canonicalized by
-// CanonicalizeHost.
-static const struct HSTSPreload* GetHSTSPreload(
- const std::string& canonicalized_host,
- const struct HSTSPreload* entries,
- size_t num_entries) {
- for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
- for (size_t j = 0; j < num_entries; j++) {
- const struct HSTSPreload* entry = entries + j;
-
- if (i != 0 && !entry->include_subdomains)
- continue;
-
- if (entry->length == canonicalized_host.size() - i &&
- memcmp(entry->dns_name, &canonicalized_host[i], entry->length) == 0) {
- return entry;
- }
- }
- }
-
- return NULL;
-}
-
-// static
-bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host,
- bool sni_available) {
- std::string canonicalized_host = CanonicalizeHost(host);
- const struct HSTSPreload* entry =
- GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS);
-
- if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts)
- return true;
-
- if (sni_available) {
- entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS,
- kNumPreloadedSNISTS);
- if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts)
- return true;
- }
-
- return false;
-}
-
-// static
-void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) {
- std::string canonicalized_host = CanonicalizeHost(host);
-
- const struct HSTSPreload* entry =
- GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS);
-
- if (!entry) {
- entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS,
- kNumPreloadedSNISTS);
- }
-
- DCHECK(entry);
- DCHECK(entry->pins.required_hashes);
- DCHECK(entry->second_level_domain_name != DOMAIN_NOT_PINNED);
-
- UMA_HISTOGRAM_ENUMERATION("Net.PublicKeyPinFailureDomain",
- entry->second_level_domain_name, DOMAIN_NUM_EVENTS);
-}
-
-// IsPreloadedSTS returns true if the canonicalized hostname should always be
-// considered to have STS enabled.
-bool TransportSecurityState::IsPreloadedSTS(
- const std::string& canonicalized_host,
- bool sni_available,
- DomainState* out) {
- DCHECK(CalledOnValidThread());
-
- out->preloaded = true;
- out->mode = DomainState::MODE_STRICT;
- out->include_subdomains = false;
-
- for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
- std::string host_sub_chunk(&canonicalized_host[i],
- canonicalized_host.size() - i);
- out->domain = DNSDomainToString(host_sub_chunk);
- std::string hashed_host(HashHost(host_sub_chunk));
- if (forced_hosts_.find(hashed_host) != forced_hosts_.end()) {
- *out = forced_hosts_[hashed_host];
- out->domain = DNSDomainToString(host_sub_chunk);
- out->preloaded = true;
- return true;
- }
- bool ret;
- if (HasPreload(kPreloadedSTS, kNumPreloadedSTS, canonicalized_host, i, out,
- &ret)) {
- return ret;
- }
- if (sni_available &&
- HasPreload(kPreloadedSNISTS, kNumPreloadedSNISTS, canonicalized_host, i,
- out, &ret)) {
- return ret;
- }
- }
-
- return false;
-}
-
-static std::string HashesToBase64String(
- const FingerprintVector& hashes) {
- std::vector<std::string> hashes_strs;
- for (FingerprintVector::const_iterator
- i = hashes.begin(); i != hashes.end(); i++) {
- std::string s;
- const std::string hash_str(reinterpret_cast<const char*>(i->data),
- sizeof(i->data));
- base::Base64Encode(hash_str, &s);
- hashes_strs.push_back(s);
- }
-
- return JoinString(hashes_strs, ',');
-}
-
-TransportSecurityState::DomainState::DomainState()
- : mode(MODE_STRICT),
- created(base::Time::Now()),
- include_subdomains(false),
- preloaded(false) {
-}
-
-TransportSecurityState::DomainState::~DomainState() {
-}
-
-bool TransportSecurityState::DomainState::IsChainOfPublicKeysPermitted(
- const FingerprintVector& hashes) {
-
- if (HashesIntersect(bad_preloaded_spki_hashes, hashes)) {
- LOG(ERROR) << "Rejecting public key chain for domain " << domain
- << ". Validated chain: " << HashesToBase64String(hashes)
- << ", matches one or more bad hashes: "
- << HashesToBase64String(bad_preloaded_spki_hashes);
- return false;
- }
-
- if (!(dynamic_spki_hashes.empty() && preloaded_spki_hashes.empty()) &&
- !HashesIntersect(dynamic_spki_hashes, hashes) &&
- !HashesIntersect(preloaded_spki_hashes, hashes)) {
- LOG(ERROR) << "Rejecting public key chain for domain " << domain
- << ". Validated chain: " << HashesToBase64String(hashes)
- << ", expected: " << HashesToBase64String(dynamic_spki_hashes)
- << " or: " << HashesToBase64String(preloaded_spki_hashes);
-
- return false;
- }
-
- return true;
-}
-
-bool TransportSecurityState::DomainState::IsMoreStrict(
- const TransportSecurityState::DomainState& other) {
- if (this->dynamic_spki_hashes.empty() && !other.dynamic_spki_hashes.empty())
- return false;
-
- if (!this->include_subdomains && other.include_subdomains)
- return false;
-
- return true;
-}
-
-bool TransportSecurityState::DomainState::ShouldRedirectHTTPToHTTPS()
- const {
- return mode == MODE_STRICT;
-}
-
-} // namespace
+#endif // NET_BASE_TRANSPORT_SECURITY_STATE_STATIC_H_
diff --git a/net/base/transport_security_state_static.json b/net/base/transport_security_state_static.json
new file mode 100644
index 0000000..16840e6
--- /dev/null
+++ b/net/base/transport_security_state_static.json
@@ -0,0 +1,267 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the HSTS preloaded list in a machine readable format.
+
+// The top-level element is a dictionary with two keys: "pinsets" maps details
+// of certificate pinning to a name and "entries" contains the HSTS details for
+// each host.
+//
+// "pinsets" is a list of objects. Each object has the following members:
+// name: (string) the name of the pinset
+// static_spki_hashes: (list of strings) the set of allowed SPKIs hashes
+// bad_static_spki_hashes: (optional list of strings) the set of forbidden SPKIs hashes
+//
+// For a given pinset, a certifiacte is accepted if at least one of the
+// "static_spki_hashes" SPKIs is found in the chain and none of the "bad_static_spki_hashes" SPKIs are.
+// SPKIs are specified as names, which must match up with the file of
+// certificates.
+//
+// "entries" is a list of objects. Each object has the following members:
+// name: (string) the DNS name of the host in question
+// include_subdomains: (optional bool) whether subdomains of |name| are also covered
+// mode: (optional string) "force-https" iff covered names should require HTTPS
+// pins: (optional string) the |name| member of an object in |pinsets|
+
+{
+ "pinsets": [
+ {
+ "name": "test",
+ "static_spki_hashes": [
+ "TestSPKI"
+ ]
+ },
+ {
+ "name": "google",
+ "static_spki_hashes": [
+ "VeriSignClass3",
+ "VeriSignClass3_G3",
+ "Google1024",
+ "Google2048",
+ "EquifaxSecureCA"
+ ],
+ "bad_static_spki_hashes": [
+ "Aetna",
+ "Intel",
+ "TCTrustCenter",
+ "Vodafone"
+ ]
+ },
+ {
+ "name": "tor",
+ "static_spki_hashes": [
+ "RapidSSL",
+ "DigiCertEVRoot",
+ "Tor1",
+ "Tor2",
+ "Tor3"
+ ]
+ },
+ {
+ "name": "twitterCom",
+ "static_spki_hashes": [
+ "VeriSignClass1",
+ "VeriSignClass3",
+ "VeriSignClass3_G4",
+ "VeriSignClass4_G3",
+ "VeriSignClass3_G3",
+ "VeriSignClass1_G3",
+ "VeriSignClass2_G3",
+ "VeriSignClass3_G2",
+ "VeriSignClass2_G2",
+ "VeriSignClass3_G5",
+ "VeriSignUniversal",
+ "GeoTrustGlobal",
+ "GeoTrustGlobal2",
+ "GeoTrustUniversal",
+ "GeoTrustUniversal2",
+ "GeoTrustPrimary",
+ "GeoTrustPrimary_G2",
+ "GeoTrustPrimary_G3",
+ "Twitter1"
+ ]
+ },
+ {
+ "name": "twitterCDN",
+ "static_spki_hashes": [
+ "VeriSignClass1",
+ "VeriSignClass3",
+ "VeriSignClass3_G4",
+ "VeriSignClass4_G3",
+ "VeriSignClass3_G3",
+ "VeriSignClass1_G3",
+ "VeriSignClass2_G3",
+ "VeriSignClass3_G2",
+ "VeriSignClass2_G2",
+ "VeriSignClass3_G5",
+ "VeriSignUniversal",
+ "GeoTrustGlobal",
+ "GeoTrustGlobal2",
+ "GeoTrustUniversal",
+ "GeoTrustUniversal2",
+ "GeoTrustPrimary",
+ "GeoTrustPrimary_G2",
+ "GeoTrustPrimary_G3",
+ "Twitter1",
+
+ "Entrust_2048",
+ "Entrust_EV",
+ "Entrust_G2",
+ "Entrust_SSL",
+ "AAACertificateServices",
+ "AddTrustClass1CARoot",
+ "AddTrustExternalCARoot",
+ "AddTrustPublicCARoot",
+ "AddTrustQualifiedCARoot",
+ "COMODOCertificationAuthority",
+ "SecureCertificateServices",
+ "TrustedCertificateServices",
+ "UTNDATACorpSGC",
+ "UTNUSERFirstClientAuthenticationandEmail",
+ "UTNUSERFirstHardware",
+ "UTNUSERFirstObject",
+ "GTECyberTrustGlobalRoot"
+ ]
+ }
+ ],
+
+ "entries": [
+ // Dummy entry to test certificate pinning.
+ { "name": "pinningtest.appspot.com", "include_subdomains": true, "pins": "test" },
+
+ // (*.)google.com, iff using SSL, must use an acceptable certificate.
+ { "name": "google.com", "include_subdomains": true, "pins": "google" },
+
+ // Now we force HTTPS for subtrees of google.com.
+ { "name": "health.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+ { "name": "checkout.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+ { "name": "chrome.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+ { "name": "docs.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+ { "name": "sites.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+ { "name": "spreadsheets.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+ { "name": "appengine.google.com", "mode": "force-https", "pins": "google" },
+ { "name": "encrypted.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+ { "name": "accounts.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+ { "name": "profiles.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+ { "name": "mail.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+ { "name": "talkgadget.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+ { "name": "talk.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+ { "name": "hostedtalkgadget.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+ { "name": "plus.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+
+ // Other Google related domain that must use HTTPS.
+ { "name": "market.android.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+ { "name": "ssl.google-analytics.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+ { "name": "drive.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+ { "name": "googleplex.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+ { "name": "groups.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+ { "name": "apis.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+
+ // chart.apis.google.com is *not* HSTS because the certificate doesn't match
+ // and there are lots of links out there that still use the name. The correct
+ // hostname for this is chart.googleapis.com.
+ { "name": "chart.apis.google.com", "include_subdomains": true, "pins": "google" },
+
+ // Other Google-related domains that must use an acceptable certificate
+ // iff using SSL.
+ { "name": "ytimg.com", "include_subdomains": true, "pins": "google" },
+ { "name": "googleusercontent.com", "include_subdomains": true, "pins": "google" },
+ { "name": "youtube.com", "include_subdomains": true, "pins": "google" },
+ { "name": "googleapis.com", "include_subdomains": true, "pins": "google" },
+ { "name": "googleadservices.com", "include_subdomains": true, "pins": "google" },
+ { "name": "googlecode.com", "include_subdomains": true, "pins": "google" },
+ { "name": "appspot.com", "include_subdomains": true, "pins": "google" },
+ { "name": "googlesyndication.com", "include_subdomains": true, "pins": "google" },
+ { "name": "doubleclick.net", "include_subdomains": true, "pins": "google" },
+ { "name": "ssl.gstatic.com", "include_subdomains": true, "pins": "google" },
+ // Exclude the learn.doubleclick.net subdomain because it uses a different
+ // CA.
+ { "name": "learn.doubleclick.net", "include_subdomains": true },
+
+ // Force HTTPS for sites that have requested it.
+ { "name": "www.paypal.com", "mode": "force-https" },
+ { "name": "www.elanex.biz", "mode": "force-https" },
+ { "name": "jottit.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sunshinepress.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "www.noisebridge.net", "mode": "force-https" },
+ { "name": "neg9.org", "mode": "force-https" },
+ { "name": "riseup.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "factor.cc", "mode": "force-https" },
+ { "name": "members.mayfirst.org", "mode": "force-https" },
+ { "name": "support.mayfirst.org", "mode": "force-https" },
+ { "name": "id.mayfirst.org", "mode": "force-https" },
+ { "name": "lists.mayfirst.org", "mode": "force-https" },
+ { "name": "splendidbacon.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "aladdinschools.appspot.com", "mode": "force-https" },
+ { "name": "ottospora.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "www.paycheckrecords.com", "mode": "force-https" },
+ { "name": "lastpass.com", "mode": "force-https" },
+ { "name": "www.lastpass.com", "mode": "force-https" },
+ { "name": "keyerror.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "entropia.de", "mode": "force-https" },
+ { "name": "www.entropia.de", "mode": "force-https" },
+ { "name": "romab.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "logentries.com", "mode": "force-https" },
+ { "name": "www.logentries.com", "mode": "force-https" },
+ { "name": "stripe.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cloudsecurityalliance.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "login.sapo.pt", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mattmccutchen.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "betnet.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "uprotect.it", "include_subdomains": true, "mode": "force-https" },
+ { "name": "squareup.com", "mode": "force-https" },
+ { "name": "cert.se", "include_subdomains": true, "mode": "force-https" },
+ { "name": "crypto.is", "include_subdomains": true, "mode": "force-https" },
+ { "name": "simon.butcher.name", "include_subdomains": true, "mode": "force-https" },
+ { "name": "linx.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dropcam.com", "mode": "force-https" },
+ { "name": "www.dropcam.com", "mode": "force-https" },
+ { "name": "ebanking.indovinabank.com.vn", "include_subdomains": true, "mode": "force-https" },
+ { "name": "epoxate.com", "mode": "force-https" },
+ { "name": "torproject.org", "mode": "force-https", "pins": "tor" },
+ { "name": "blog.torproject.org", "include_subdomains": true, "mode": "force-https", "pins": "tor" },
+ { "name": "check.torproject.org", "include_subdomains": true, "mode": "force-https", "pins": "tor" },
+ { "name": "www.torproject.org", "include_subdomains": true, "mode": "force-https", "pins": "tor" },
+ { "name": "www.moneybookers.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ledgerscope.net", "mode": "force-https" },
+ { "name": "www.ledgerscope.net", "mode": "force-https" },
+ { "name": "kyps.net", "mode": "force-https" },
+ { "name": "www.kyps.net", "mode": "force-https" },
+ { "name": "app.recurly.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "api.recurly.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "greplin.com", "mode": "force-https" },
+ { "name": "www.greplin.com", "mode": "force-https" },
+ { "name": "luneta.nearbuysystems.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ubertt.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pixi.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "grepular.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mydigipass.com", "mode": "force-https" },
+ { "name": "www.mydigipass.com", "mode": "force-https" },
+ { "name": "developer.mydigipass.com", "mode": "force-https" },
+ { "name": "www.developer.mydigipass.com", "mode": "force-https" },
+ { "name": "sandbox.mydigipass.com", "mode": "force-https" },
+ { "name": "www.sandbox.mydigipass.com", "mode": "force-https" },
+ { "name": "crypto.cat", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bigshinylock.minazo.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "crate.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "twitter.com", "pins": "twitterCom" },
+ { "name": "www.twitter.com", "include_subdomains": true, "pins": "twitterCom" },
+ { "name": "api.twitter.com", "include_subdomains": true, "pins": "twitterCDN" },
+ { "name": "oauth.twitter.com", "include_subdomains": true, "pins": "twitterCom" },
+ { "name": "mobile.twitter.com", "include_subdomains": true, "pins": "twitterCom" },
+ { "name": "dev.twitter.com", "include_subdomains": true, "pins": "twitterCom" },
+ { "name": "business.twitter.com", "include_subdomains": true, "pins": "twitterCom" },
+ { "name": "platform.twitter.com", "include_subdomains": true, "pins": "twitterCDN" },
+ { "name": "si0.twimg.com", "include_subdomains": true, "pins": "twitterCDN" },
+ { "name": "twimg0-a.akamaihd.net", "include_subdomains": true, "pins": "twitterCDN" },
+
+ // Entries that are only valid if the client supports SNI.
+ { "name": "gmail.com", "mode": "force-https", "pins": "google", "snionly": true },
+ { "name": "googlemail.com", "mode": "force-https", "pins": "google", "snionly": true },
+ { "name": "www.gmail.com", "mode": "force-https", "pins": "google", "snionly": true },
+ { "name": "www.googlemail.com", "mode": "force-https", "pins": "google", "snionly": true },
+ { "name": "google-analytics.com", "include_subdomains": true, "pins": "google", "snionly": true },
+ { "name": "googlegroups.com", "include_subdomains": true, "pins": "google", "snionly": true }
+ ]
+}
diff --git a/net/base/transport_security_state_static_generate.go b/net/base/transport_security_state_static_generate.go
new file mode 100644
index 0000000..03694f9
--- /dev/null
+++ b/net/base/transport_security_state_static_generate.go
@@ -0,0 +1,547 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This program converts the information in
+// transport_security_state_static.json and
+// transport_security_state_static.certs into
+// transport_security_state_static.h. The input files contain information about
+// public key pinning and HTTPS-only sites that is compiled into Chromium.
+
+// Run as:
+// % go run transport_security_state_static_generate.go transport_security_state_static.json transport_security_state_static.certs
+//
+// It will write transport_security_state_static.h
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "crypto/sha1"
+ "crypto/x509"
+ "encoding/base64"
+ "encoding/json"
+ "encoding/pem"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "regexp"
+ "strings"
+)
+
+// A pin represents an entry in transport_security_state_static.certs. It's a
+// name associated with a SubjectPublicKeyInfo hash and, optionally, a
+// certificate.
+type pin struct {
+ name string
+ cert *x509.Certificate
+ spkiHash []byte
+ spkiHashFunc string // i.e. "sha1"
+}
+
+// preloaded represents the information contained in the
+// transport_security_state_static.json file. This structure and the two
+// following are used by the "json" package to parse the file. See the comments
+// in transport_security_state_static.json for details.
+type preloaded struct {
+ Pinsets []pinset `json:"pinsets"`
+ Entries []hsts `json:"entries"`
+}
+
+type pinset struct {
+ Name string `json:"name"`
+ Include []string `json:"static_spki_hashes"`
+ Exclude []string `json:"bad_static_spki_hashes"`
+}
+
+type hsts struct {
+ Name string `json:"name"`
+ Subdomains bool `json:"include_subdomains"`
+ Mode string `json:"mode"`
+ Pins string `json:"pins"`
+ SNIOnly bool `json:"snionly"`
+}
+
+func main() {
+ if len(os.Args) != 3 {
+ fmt.Fprintf(os.Stderr, "Usage: %s <json file> <certificates file>\n", os.Args[0])
+ os.Exit(1)
+ }
+
+ if err := process(os.Args[1], os.Args[2]); err != nil {
+ fmt.Fprintf(os.Stderr, "Conversion failed: %s\n", err.Error())
+ os.Exit(1)
+ }
+}
+
+func process(jsonFileName, certsFileName string) error {
+ jsonFile, err := os.Open(jsonFileName)
+ if err != nil {
+ return fmt.Errorf("failed to open input file: %s\n", err.Error())
+ }
+ defer jsonFile.Close()
+
+ jsonBytes, err := removeComments(jsonFile)
+ if err != nil {
+ return fmt.Errorf("failed to remove comments from JSON: %s\n", err.Error())
+ }
+
+ var preloaded preloaded
+ if err := json.Unmarshal(jsonBytes, &preloaded); err != nil {
+ return fmt.Errorf("failed to parse JSON: %s\n", err.Error())
+ }
+
+ certsFile, err := os.Open(certsFileName)
+ if err != nil {
+ return fmt.Errorf("failed to open input file: %s\n", err.Error())
+ }
+ defer certsFile.Close()
+
+ pins, err := parseCertsFile(certsFile)
+ if err != nil {
+ return fmt.Errorf("failed to parse certificates file: %s\n", err)
+ }
+
+ if err := checkDuplicatePins(pins); err != nil {
+ return err
+ }
+
+ if err := checkCertsInPinsets(preloaded.Pinsets, pins); err != nil {
+ return err
+ }
+
+ outFile, err := os.OpenFile("transport_security_state_static.h", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
+ if err != nil {
+ return err
+ }
+ defer outFile.Close()
+
+ out := bufio.NewWriter(outFile)
+ writeHeader(out)
+ writeCertsOutput(out, pins)
+ writeHSTSOutput(out, preloaded)
+ writeFooter(out)
+ out.Flush()
+
+ return nil
+}
+
+var newLine = []byte("\n")
+var startOfCert = []byte("-----BEGIN CERTIFICATE")
+var endOfCert = []byte("-----END CERTIFICATE")
+var startOfSHA1 = []byte("sha1/")
+
+// nameRegexp matches valid pin names: an uppercase letter followed by zero or
+// more letters and digits.
+var nameRegexp = regexp.MustCompile("[A-Z][a-zA-Z0-9_]*")
+
+// commentRegexp matches lines that optionally start with whitespace
+// followed by "//".
+var commentRegexp = regexp.MustCompile("^[ \t]*//")
+
+// removeComments reads the contents of |r| and removes any lines beginning
+// with optional whitespace followed by "//"
+func removeComments(r io.Reader) ([]byte, error) {
+ var buf bytes.Buffer
+ in := bufio.NewReader(r)
+
+ for {
+ line, isPrefix, err := in.ReadLine()
+ if isPrefix {
+ return nil, errors.New("line too long in JSON")
+ }
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return nil, err
+ }
+ if commentRegexp.Match(line) {
+ continue
+ }
+ buf.Write(line)
+ buf.Write(newLine)
+ }
+
+ return buf.Bytes(), nil
+}
+
+// parseCertsFile parses |inFile|, in the format of
+// transport_security_state_static.certs. See the comments at the top of that
+// file for details of the format.
+func parseCertsFile(inFile io.Reader) ([]pin, error) {
+ const (
+ PRENAME = iota
+ POSTNAME = iota
+ INCERT = iota
+ )
+
+ in := bufio.NewReader(inFile)
+
+ lineNo := 0
+ var pemCert []byte
+ state := PRENAME
+ var name string
+ var pins []pin
+
+ for {
+ lineNo++
+ line, isPrefix, err := in.ReadLine()
+ if isPrefix {
+ return nil, fmt.Errorf("line %d is too long to process\n", lineNo)
+ }
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return nil, fmt.Errorf("error reading from input: %s\n", err.Error())
+ }
+
+ if len(line) == 0 || line[0] == '#' {
+ continue
+ }
+
+ switch state {
+ case PRENAME:
+ name = string(line)
+ if !nameRegexp.MatchString(name) {
+ return nil, fmt.Errorf("invalid name on line %d\n", lineNo)
+ }
+ state = POSTNAME
+ case POSTNAME:
+ switch {
+ case bytes.HasPrefix(line, startOfSHA1):
+ hash, err := base64.StdEncoding.DecodeString(string(line[len(startOfSHA1):]))
+ if err != nil {
+ return nil, fmt.Errorf("failed to decode hash on line %d: %s\n", lineNo, err)
+ }
+ if len(hash) != 20 {
+ return nil, fmt.Errorf("bad SHA1 hash length on line %d: %s\n", lineNo, err)
+ }
+ pins = append(pins, pin{
+ name: name,
+ spkiHashFunc: "sha1",
+ spkiHash: hash,
+ })
+ state = PRENAME
+ continue
+ case bytes.HasPrefix(line, startOfCert):
+ pemCert = pemCert[:0]
+ pemCert = append(pemCert, line...)
+ pemCert = append(pemCert, '\n')
+ state = INCERT
+ default:
+ return nil, fmt.Errorf("line %d, after a name, is not a hash nor a certificate\n", lineNo)
+ }
+ case INCERT:
+ pemCert = append(pemCert, line...)
+ pemCert = append(pemCert, '\n')
+ if !bytes.HasPrefix(line, endOfCert) {
+ continue
+ }
+
+ block, _ := pem.Decode(pemCert)
+ if block == nil {
+ return nil, fmt.Errorf("failed to decode certificate ending on line %d\n", lineNo)
+ }
+ cert, err := x509.ParseCertificate(block.Bytes)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse certificate ending on line %d: %s\n", lineNo, err.Error())
+ }
+ certName := cert.Subject.CommonName
+ if len(certName) == 0 {
+ certName = cert.Subject.Organization[0] + " " + cert.Subject.OrganizationalUnit[0]
+ }
+ if err := matchNames(certName, name); err != nil {
+ return nil, fmt.Errorf("name failure on line %d: %s\n%s -> %s\n", lineNo, err, certName, name)
+ }
+ h := sha1.New()
+ h.Write(cert.RawSubjectPublicKeyInfo)
+ pins = append(pins, pin{
+ name: name,
+ cert: cert,
+ spkiHashFunc: "sha1",
+ spkiHash: h.Sum(nil),
+ })
+ state = PRENAME
+ }
+ }
+
+ return pins, nil
+}
+
+// matchNames returns true if the given pin name is a reasonable match for the
+// given CN.
+func matchNames(name, v string) error {
+ words := strings.Split(name, " ")
+ if len(words) == 0 {
+ return errors.New("no words in certificate name")
+ }
+ firstWord := words[0]
+ if strings.HasSuffix(firstWord, ",") {
+ firstWord = firstWord[:len(firstWord)-1]
+ }
+ if pos := strings.Index(firstWord, "."); pos != -1 {
+ firstWord = firstWord[:pos]
+ }
+ if pos := strings.Index(firstWord, "-"); pos != -1 {
+ firstWord = firstWord[:pos]
+ }
+ if !strings.HasPrefix(v, firstWord) {
+ return errors.New("the first word of the certificate name isn't a prefix of the variable name")
+ }
+
+ for i, word := range words {
+ if word == "Class" && i+1 < len(words) {
+ if strings.Index(v, word+words[i+1]) == -1 {
+ return errors.New("class specification doesn't appear in the variable name")
+ }
+ } else if len(word) == 1 && word[0] >= '0' && word[0] <= '9' {
+ if strings.Index(v, word) == -1 {
+ return errors.New("number doesn't appear in the variable name")
+ }
+ } else if isImportantWordInCertificateName(word) {
+ if strings.Index(v, word) == -1 {
+ return errors.New(word + " doesn't appear in the variable name")
+ }
+ }
+ }
+
+ return nil
+}
+
+// isImportantWordInCertificateName returns true if w must be found in any
+// corresponding variable name.
+func isImportantWordInCertificateName(w string) bool {
+ switch w {
+ case "Universal", "Global", "EV", "G1", "G2", "G3", "G4", "G5":
+ return true
+ }
+ return false
+}
+
+// checkDuplicatePins returns an error if any pins have the same name or the same hash.
+func checkDuplicatePins(pins []pin) error {
+ seenNames := make(map[string]bool)
+ seenHashes := make(map[string]string)
+
+ for _, pin := range pins {
+ if _, ok := seenNames[pin.name]; ok {
+ return fmt.Errorf("duplicate name: %s", pin.name)
+ }
+ seenNames[pin.name] = true
+
+ strHash := string(pin.spkiHash)
+ if otherName, ok := seenHashes[strHash]; ok {
+ return fmt.Errorf("duplicate hash for %s and %s", pin.name, otherName)
+ }
+ seenHashes[strHash] = pin.name
+ }
+
+ return nil
+}
+
+// checkCertsInPinsets returns an error if
+// a) unknown pins are mentioned in |pinsets|
+// b) unused pins are given in |pins|
+// c) a pinset name is used twice
+func checkCertsInPinsets(pinsets []pinset, pins []pin) error {
+ pinNames := make(map[string]bool)
+ for _, pin := range pins {
+ pinNames[pin.name] = true
+ }
+
+ usedPinNames := make(map[string]bool)
+ pinsetNames := make(map[string]bool)
+
+ for _, pinset := range pinsets {
+ if _, ok := pinsetNames[pinset.Name]; ok {
+ return fmt.Errorf("duplicate pinset name: %s", pinset.Name)
+ }
+ pinsetNames[pinset.Name] = true
+
+ var allPinNames []string
+ allPinNames = append(allPinNames, pinset.Include...)
+ allPinNames = append(allPinNames, pinset.Exclude...)
+
+ for _, pinName := range allPinNames {
+ if _, ok := pinNames[pinName]; !ok {
+ return fmt.Errorf("unknown pin: %s", pinName)
+ }
+ usedPinNames[pinName] = true
+ }
+ }
+
+ for pinName := range pinNames {
+ if _, ok := usedPinNames[pinName]; !ok {
+ return fmt.Errorf("unused pin: %s", pinName)
+ }
+ }
+
+ return nil
+}
+
+func writeHeader(out *bufio.Writer) {
+ out.WriteString(`// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is automatically generated by transport_security_state_static_generate.go
+
+#ifndef NET_BASE_TRANSPORT_SECURITY_STATE_STATIC_H_
+#define NET_BASE_TRANSPORT_SECURITY_STATE_STATIC_H_
+#pragma once
+
+`)
+
+}
+
+func writeFooter(out *bufio.Writer) {
+ out.WriteString("#endif // NET_BASE_TRANSPORT_SECURITY_STATE_STATIC_H_\n")
+}
+
+func writeCertsOutput(out *bufio.Writer, pins []pin) {
+ out.WriteString(`// These are SubjectPublicKeyInfo hashes for public key pinning. The
+// hashes are base64 encoded, SHA1 digests.
+
+`)
+
+ for _, pin := range pins {
+ if pin.cert != nil {
+ out.WriteString("#if 0\n")
+ pem.Encode(out, &pem.Block{Type: "CERTIFICATE", Bytes: pin.cert.Raw})
+ out.WriteString("#endif\n")
+ }
+ fmt.Fprintf(out, "static const char kSPKIHash_%s[] =\n", pin.name)
+ fmt.Fprintf(out, " \"%s/%s\";\n\n", pin.spkiHashFunc, base64.StdEncoding.EncodeToString(pin.spkiHash))
+ }
+}
+
+// uppercaseFirstLetter returns s with the first letter uppercased.
+func uppercaseFirstLetter(s string) string {
+ // We need to find the index of the second code-point, which may not be
+ // one.
+ for i := range s {
+ if i == 0 {
+ continue
+ }
+ return strings.ToUpper(s[:i]) + s[i:]
+ }
+ return strings.ToUpper(s)
+}
+
+func writeListOfPins(w io.Writer, name string, pinNames []string) {
+ fmt.Fprintf(w, "static const char* const %s[] = {\n", name)
+ for _, pinName := range pinNames {
+ fmt.Fprintf(w, " kSPKIHash_%s,\n", pinName)
+ }
+ fmt.Fprintf(w, " NULL,\n};\n")
+}
+
+// toDNS returns a string converts the domain name |s| into C-escaped,
+// length-prefixed form and also returns the length of the interpreted string.
+// i.e. for an input "example.com" it will return "\\007example\\003com", 13.
+func toDNS(s string) (string, int) {
+ labels := strings.Split(s, ".")
+
+ var name string
+ var l int
+ for _, label := range labels {
+ if len(label) > 63 {
+ panic("DNS label too long")
+ }
+ name += fmt.Sprintf("\\%03o", len(label))
+ name += label
+ l += len(label) + 1
+ }
+ l += 1 // For the length of the root label.
+
+ return name, l
+}
+
+// domainConstant converts the domain name |s| into a string of the form
+// "DOMAIN_" + uppercase last two labels.
+func domainConstant(s string) string {
+ labels := strings.Split(s, ".")
+ gtld := strings.ToUpper(labels[len(labels)-1])
+ domain := strings.Replace(strings.ToUpper(labels[len(labels)-2]), "-", "_", -1)
+
+ return fmt.Sprintf("DOMAIN_%s_%s", domain, gtld)
+}
+
+func writeHSTSEntry(out *bufio.Writer, entry hsts) {
+ dnsName, dnsLen := toDNS(entry.Name)
+ domain := "DOMAIN_NOT_PINNED"
+ pinsetName := "kNoPins"
+ if len(entry.Pins) > 0 {
+ pinsetName = fmt.Sprintf("k%sPins", uppercaseFirstLetter(entry.Pins))
+ domain = domainConstant(entry.Name)
+ }
+ fmt.Fprintf(out, " {%d, %t, \"%s\", %t, %s, %s },\n", dnsLen, entry.Subdomains, dnsName, entry.Mode == "force-https", pinsetName, domain)
+}
+
+func writeHSTSOutput(out *bufio.Writer, hsts preloaded) error {
+ out.WriteString(`// The following is static data describing the hosts that are hardcoded with
+// certificate pins or HSTS information.
+
+// kNoRejectedPublicKeys is a placeholder for when no public keys are rejected.
+static const char* const kNoRejectedPublicKeys[] = {
+ NULL,
+};
+
+`)
+
+ for _, pinset := range hsts.Pinsets {
+ name := uppercaseFirstLetter(pinset.Name)
+ acceptableListName := fmt.Sprintf("k%sAcceptableCerts", name)
+ writeListOfPins(out, acceptableListName, pinset.Include)
+
+ rejectedListName := "kNoRejectedPublicKeys"
+ if len(pinset.Exclude) > 0 {
+ rejectedListName = fmt.Sprintf("k%sRejectedCerts", name)
+ writeListOfPins(out, rejectedListName, pinset.Exclude)
+ }
+ fmt.Fprintf(out, `#define k%sPins { \
+ %s, \
+ %s, \
+}
+
+`, name, acceptableListName, rejectedListName)
+ }
+
+ out.WriteString(`#define kNoPins {\
+ NULL, NULL, \
+}
+
+static const struct HSTSPreload kPreloadedSTS[] = {
+`)
+
+ for _, entry := range hsts.Entries {
+ if entry.SNIOnly {
+ continue
+ }
+ writeHSTSEntry(out, entry)
+ }
+
+ out.WriteString(`};
+static const size_t kNumPreloadedSTS = ARRAYSIZE_UNSAFE(kPreloadedSTS);
+
+static const struct HSTSPreload kPreloadedSNISTS[] = {
+`)
+
+ for _, entry := range hsts.Entries {
+ if !entry.SNIOnly {
+ continue
+ }
+ writeHSTSEntry(out, entry)
+ }
+
+ out.WriteString(`};
+static const size_t kNumPreloadedSNISTS = ARRAYSIZE_UNSAFE(kPreloadedSNISTS);
+
+`)
+
+ return nil
+}
diff --git a/net/net.gyp b/net/net.gyp
index d33fc22..b6288de 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -253,6 +253,7 @@
'base/test_root_certs_win.cc',
'base/transport_security_state.cc',
'base/transport_security_state.h',
+ 'base/transport_security_state_static.h',
'base/upload_data.cc',
'base/upload_data.h',
'base/upload_data_stream.cc',