diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-11 18:56:44 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-11 18:56:44 +0000 |
commit | 7f82d4bb6f981a3149ba9f79b51fd5fd7e9b77a8 (patch) | |
tree | 030b59d231331d5a4319534224a77232fbb99e9a /net | |
parent | e13e2b7514ba4be99aaf6ae415f03cf4dcb9cb2d (diff) | |
download | chromium_src-7f82d4bb6f981a3149ba9f79b51fd5fd7e9b77a8.zip chromium_src-7f82d4bb6f981a3149ba9f79b51fd5fd7e9b77a8.tar.gz chromium_src-7f82d4bb6f981a3149ba9f79b51fd5fd7e9b77a8.tar.bz2 |
Move tools out of Chromium repo
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@156081 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/ssl_cipher_suite_names_generate.go | 189 | ||||
-rw-r--r-- | net/base/transport_security_state_static_generate.go | 586 |
2 files changed, 0 insertions, 775 deletions
diff --git a/net/base/ssl_cipher_suite_names_generate.go b/net/base/ssl_cipher_suite_names_generate.go deleted file mode 100644 index 6366c1f..0000000 --- a/net/base/ssl_cipher_suite_names_generate.go +++ /dev/null @@ -1,189 +0,0 @@ -// This program reads in the contents of [1] from /tmp/tls-parameters.xml and -// writes out a compact form the ciphersuite information found there in. -// It's used to generate the tables in net/base/ssl_cipher_suite_names.cc -// -// [1] http://www.iana.org/assignments/tls-parameters/tls-parameters.xml -package main - -import ( - "encoding/xml" - "fmt" - "os" - "sort" - "strings" -) - -// Structures for parsing the XML - -type TLSRegistry struct { - Registry []Registry `xml:"registry"` -} - -type Registry struct { - Id string `xml:"id,attr"` - Title string `xml:"title"` - Record []Record `xml:"record"` -} - -type Record struct { - Value string `xml:"value"` - Description string `xml:"description"` -} - -type CipherSuite struct { - value uint16 - kx string - cipher string - mac string -} - -func fromHex(c byte) int { - if c >= '0' && c <= '9' { - return int(c - '0') - } - if c >= 'a' && c <= 'f' { - return int(c - 'a' + 10) - } - if c >= 'A' && c <= 'F' { - return int(c - 'A' + 10) - } - panic("Bad char passed to fromHex") -} - -type TLSValue struct { - v int - name string -} - -type TLSMapping []TLSValue - -func (m TLSMapping) Len() int { - return len(m) -} - -func (m TLSMapping) Less(i, j int) bool { - return m[i].v < m[j].v -} - -func (m TLSMapping) Swap(i, j int) { - m[i], m[j] = m[j], m[i] -} - -func printDict(d map[string]int, name string) { - a := make([]TLSValue, len(d)) - - maxLen := 0 - i := 0 - for k, v := range d { - if len(k) > maxLen { - maxLen = len(k) - } - a[i].v = v - a[i].name = k - i++ - } - - sort.Sort(TLSMapping(a)) - - fmt.Printf("static const struct {\n char name[%d];\n} %s[%d] = {\n", maxLen+1, name, len(d)) - for _, m := range a { - fmt.Printf(" {\"%s\"}, // %d\n", m.name, m.v) - } - - fmt.Printf("};\n\n") -} - -func parseCipherSuiteString(s string) (kx, cipher, mac string) { - s = s[4:] - i := strings.Index(s, "_WITH_") - kx = s[0:i] - s = s[i+6:] - i = strings.LastIndex(s, "_") - cipher = s[0:i] - mac = s[i+1:] - return -} - -func main() { - infile, err := os.Open("/tmp/tls-parameters.xml") - if err != nil { - fmt.Printf("Cannot open input: %s\n", err) - return - } - - var input TLSRegistry - err = xml.NewDecoder(infile).Decode(&input) - if err != nil { - fmt.Printf("Error parsing XML: %s\n", err) - return - } - - var cipherSuitesRegistry *Registry - for _, r := range input.Registry { - if r.Id == "tls-parameters-4" { - cipherSuitesRegistry = &r - break - } - } - - if cipherSuitesRegistry == nil { - fmt.Printf("Didn't find tls-parameters-4 registry\n") - } - - kxs := make(map[string]int) - next_kx := 0 - ciphers := make(map[string]int) - next_cipher := 0 - macs := make(map[string]int) - next_mac := 0 - lastValue := uint16(0) - - fmt.Printf("struct CipherSuite {\n uint16 cipher_suite, encoded;\n};\n\n") - fmt.Printf("static const struct CipherSuite kCipherSuites[] = {\n") - - for _, r := range cipherSuitesRegistry.Record { - if strings.Index(r.Description, "_WITH_") == -1 { - continue - } - - value := uint16(fromHex(r.Value[2])<<12 | fromHex(r.Value[3])<<8 | fromHex(r.Value[7])<<4 | fromHex(r.Value[8])) - kx, cipher, mac := parseCipherSuiteString(r.Description) - - if value < lastValue { - panic("Input isn't sorted") - } - lastValue = value - - var kx_n, cipher_n, mac_n int - var ok bool - - if kx_n, ok = kxs[kx]; !ok { - kxs[kx] = next_kx - kx_n = next_kx - next_kx++ - } - if cipher_n, ok = ciphers[cipher]; !ok { - ciphers[cipher] = next_cipher - cipher_n = next_cipher - next_cipher++ - } - if mac_n, ok = macs[mac]; !ok { - macs[mac] = next_mac - mac_n = next_mac - next_mac++ - } - - if kx_n > 32 || cipher_n > 15 || mac_n > 7 { - panic("Need to shift bit boundaries") - } - - encoded := (kx_n << 7) | (cipher_n << 3) | mac_n - fmt.Printf(" {0x%x, 0x%x}, // %s\n", value, encoded, r.Description) - } - - fmt.Printf("};\n\n") - - printDict(kxs, "kKeyExchangeNames") - printDict(ciphers, "kCipherNames") - printDict(macs, "kMacNames") -} diff --git a/net/base/transport_security_state_static_generate.go b/net/base/transport_security_state_static_generate.go deleted file mode 100644 index cb2154f..0000000 --- a/net/base/transport_security_state_static_generate.go +++ /dev/null @@ -1,586 +0,0 @@ -// 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 - } - - if err := checkNoopEntries(preloaded.Entries); err != nil { - return err - } - - if err := checkDuplicateEntries(preloaded.Entries); 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 strings.HasPrefix(firstWord, "*.") { - firstWord = firstWord[2:] - } - if pos := strings.Index(firstWord, "."); pos != -1 { - firstWord = firstWord[:pos] - } - if pos := strings.Index(firstWord, "-"); pos != -1 { - firstWord = firstWord[:pos] - } - if len(firstWord) == 0 { - return errors.New("first word of certificate name is empty") - } - firstWord = strings.ToLower(firstWord) - lowerV := strings.ToLower(v) - if !strings.HasPrefix(lowerV, 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 checkNoopEntries(entries []hsts) error { - for _, e := range entries { - if len(e.Mode) == 0 && len(e.Pins) == 0 { - switch e.Name { - // This entry is deliberately used as an exclusion. - case "learn.doubleclick.net": - continue - default: - return errors.New("Entry for " + e.Name + " has no mode and no pins") - } - } - } - - return nil -} - -func checkDuplicateEntries(entries []hsts) error { - seen := make(map[string]bool) - - for _, e := range entries { - if _, ok := seen[e.Name]; ok { - return errors.New("Duplicate entry for " + e.Name) - } - seen[e.Name] = true - } - - 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_ - -`) - -} - -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 { - 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 -} |