// 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 (
"fmt"
"os"
"sort"
"strings"
"xml"
)
// Structures for parsing the XML
type TLSRegistry struct {
Registry []Registry
}
type Registry struct {
Id string "attr"
Title string
Record []Record
}
type Record struct {
Value string
Description string
}
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", os.O_RDONLY, 0)
if err != nil {
fmt.Printf("Cannot open input: %s\n", err)
return
}
var input TLSRegistry
err = xml.Unmarshal(infile, &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")
}