• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2015 The BoringSSL Authors
2//
3// Permission to use, copy, modify, and/or distribute this software for any
4// purpose with or without fee is hereby granted, provided that the above
5// copyright notice and this permission notice appear in all copies.
6//
7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15package main
16
17import (
18	"bufio"
19	"bytes"
20	"errors"
21	"fmt"
22	"io"
23	"os"
24	"path"
25	"sort"
26	"strconv"
27)
28
29// libraryNames must be kept in sync with the enum in err.h. The generated code
30// will contain static assertions to enforce this.
31var libraryNames = []string{
32	"NONE",
33	"SYS",
34	"BN",
35	"RSA",
36	"DH",
37	"EVP",
38	"BUF",
39	"OBJ",
40	"PEM",
41	"DSA",
42	"X509",
43	"ASN1",
44	"CONF",
45	"CRYPTO",
46	"EC",
47	"SSL",
48	"BIO",
49	"PKCS7",
50	"PKCS8",
51	"X509V3",
52	"RAND",
53	"ENGINE",
54	"OCSP",
55	"UI",
56	"COMP",
57	"ECDSA",
58	"ECDH",
59	"HMAC",
60	"DIGEST",
61	"CIPHER",
62	"HKDF",
63	"TRUST_TOKEN",
64	"USER",
65}
66
67// stringList is a map from uint32 -> string which can output data for a sorted
68// list as C literals.
69type stringList struct {
70	// entries is an array of keys and offsets into |stringData|. The
71	// offsets are in the bottom 15 bits of each uint32 and the key is the
72	// top 17 bits.
73	entries []uint32
74	// internedStrings contains the same strings as are in |stringData|,
75	// but allows for easy deduplication. It maps a string to its offset in
76	// |stringData|.
77	internedStrings map[string]uint32
78	stringData      []byte
79}
80
81func newStringList() *stringList {
82	return &stringList{
83		internedStrings: make(map[string]uint32),
84	}
85}
86
87// offsetMask is the bottom 15 bits. It's a mask that selects the offset from a
88// uint32 in entries.
89const offsetMask = 0x7fff
90
91func (st *stringList) Add(key uint32, value string) error {
92	if key&offsetMask != 0 {
93		return errors.New("need bottom 15 bits of the key for the offset")
94	}
95	offset, ok := st.internedStrings[value]
96	if !ok {
97		offset = uint32(len(st.stringData))
98		if offset&offsetMask != offset {
99			return errors.New("stringList overflow")
100		}
101		st.stringData = append(st.stringData, []byte(value)...)
102		st.stringData = append(st.stringData, 0)
103		st.internedStrings[value] = offset
104	}
105
106	for _, existing := range st.entries {
107		if existing>>15 == key>>15 {
108			panic("duplicate entry")
109		}
110	}
111	st.entries = append(st.entries, key|offset)
112	return nil
113}
114
115func (st *stringList) buildList() []uint32 {
116	sort.Slice(st.entries, func(i, j int) bool { return (st.entries[i] >> 15) < (st.entries[j] >> 15) })
117	return st.entries
118}
119
120type stringWriter interface {
121	io.Writer
122	WriteString(string) (int, error)
123}
124
125func (st *stringList) WriteTo(out stringWriter, name string) {
126	list := st.buildList()
127	values := "kOpenSSL" + name + "Values"
128	out.WriteString("extern const uint32_t " + values + "[];\n")
129	out.WriteString("const uint32_t " + values + "[] = {\n")
130	for _, v := range list {
131		fmt.Fprintf(out, "    0x%x,\n", v)
132	}
133	out.WriteString("};\n\n")
134	out.WriteString("extern const size_t " + values + "Len;\n")
135	out.WriteString("const size_t " + values + "Len = sizeof(" + values + ") / sizeof(" + values + "[0]);\n\n")
136
137	stringData := "kOpenSSL" + name + "StringData"
138	out.WriteString("extern const char " + stringData + "[];\n")
139	out.WriteString("const char " + stringData + "[] =\n    \"")
140	for i, c := range st.stringData {
141		if c == 0 {
142			out.WriteString("\\0\"\n    \"")
143			continue
144		}
145		out.Write(st.stringData[i : i+1])
146	}
147	out.WriteString("\";\n\n")
148}
149
150type errorData struct {
151	reasons    *stringList
152	libraryMap map[string]uint32
153}
154
155func (e *errorData) readErrorDataFile(filename string) error {
156	inFile, err := os.Open(filename)
157	if err != nil {
158		return err
159	}
160	defer inFile.Close()
161
162	scanner := bufio.NewScanner(inFile)
163	comma := []byte(",")
164
165	lineNo := 0
166	for scanner.Scan() {
167		lineNo++
168
169		line := scanner.Bytes()
170		if len(line) == 0 {
171			continue
172		}
173		parts := bytes.Split(line, comma)
174		if len(parts) != 3 {
175			return fmt.Errorf("bad line %d in %s: found %d values but want 3", lineNo, filename, len(parts))
176		}
177		libNum, ok := e.libraryMap[string(parts[0])]
178		if !ok {
179			return fmt.Errorf("bad line %d in %s: unknown library", lineNo, filename)
180		}
181		if libNum >= 64 {
182			return fmt.Errorf("bad line %d in %s: library value too large", lineNo, filename)
183		}
184		key, err := strconv.ParseUint(string(parts[1]), 10 /* base */, 32 /* bit size */)
185		if err != nil {
186			return fmt.Errorf("bad line %d in %s: %s", lineNo, filename, err)
187		}
188		if key >= 2048 {
189			return fmt.Errorf("bad line %d in %s: key too large", lineNo, filename)
190		}
191		value := string(parts[2])
192
193		listKey := libNum<<26 | uint32(key)<<15
194
195		err = e.reasons.Add(listKey, value)
196		if err != nil {
197			return err
198		}
199	}
200
201	return scanner.Err()
202}
203
204type ErrDataTask struct {
205	TargetName string
206	Inputs     []string
207}
208
209func (t *ErrDataTask) Destination() string {
210	return path.Join("gen", t.TargetName, "err_data.cc")
211}
212
213func (t *ErrDataTask) Run() ([]byte, error) {
214	e := &errorData{
215		reasons:    newStringList(),
216		libraryMap: make(map[string]uint32),
217	}
218	for i, name := range libraryNames {
219		e.libraryMap[name] = uint32(i) + 1
220	}
221
222	for _, input := range t.Inputs {
223		if err := e.readErrorDataFile(input); err != nil {
224			return nil, err
225		}
226	}
227
228	var out bytes.Buffer
229	out.WriteString(`/* Copyright 2015 The BoringSSL Authors
230 *
231 * Permission to use, copy, modify, and/or distribute this software for any
232 * purpose with or without fee is hereby granted, provided that the above
233 * copyright notice and this permission notice appear in all copies.
234 *
235 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
236 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
237 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
238 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
239 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
240 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
241 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
242
243 /* This file was generated by go run ./util/pregenerate. */
244
245#include <openssl/base.h>
246#include <openssl/err.h>
247
248#include <assert.h>
249
250`)
251
252	for i, name := range libraryNames {
253		fmt.Fprintf(&out, "static_assert(ERR_LIB_%s == %d, \"library value changed\");\n", name, i+1)
254	}
255	fmt.Fprintf(&out, "static_assert(ERR_NUM_LIBS == %d, \"number of libraries changed\");\n", len(libraryNames)+1)
256	out.WriteString("\n")
257
258	e.reasons.WriteTo(&out, "Reason")
259	return out.Bytes(), nil
260}
261