1// Copyright (c) 2016, Google Inc.
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/ioutil"
23	"os"
24	"os/exec"
25	"sort"
26	"strconv"
27	"strings"
28)
29
30func sanitizeName(in string) string {
31	in = strings.Replace(in, "-", "_", -1)
32	in = strings.Replace(in, ".", "_", -1)
33	in = strings.Replace(in, " ", "_", -1)
34	return in
35}
36
37type object struct {
38	name string
39	// shortName and longName are the short and long names, respectively. If
40	// one is missing, it takes the value of the other, but the
41	// corresponding SN_foo or LN_foo macro is not defined.
42	shortName, longName       string
43	hasShortName, hasLongName bool
44	oid                       []int
45	encoded                   []byte
46}
47
48type objects struct {
49	// byNID is the list of all objects, indexed by nid.
50	byNID []object
51	// nameToNID is a map from object name to nid.
52	nameToNID map[string]int
53}
54
55func readNumbers(path string) (nameToNID map[string]int, numNIDs int, err error) {
56	in, err := os.Open(path)
57	if err != nil {
58		return nil, 0, err
59	}
60	defer in.Close()
61
62	nameToNID = make(map[string]int)
63	nidsSeen := make(map[int]struct{})
64
65	// Reserve NID 0 for NID_undef.
66	numNIDs = 1
67	nameToNID["undef"] = 0
68	nidsSeen[0] = struct{}{}
69
70	var lineNo int
71	scanner := bufio.NewScanner(in)
72	for scanner.Scan() {
73		line := scanner.Text()
74		lineNo++
75		withLine := func(err error) error {
76			return fmt.Errorf("%s:%d: %s", path, lineNo, err)
77		}
78
79		fields := strings.Fields(line)
80		if len(fields) == 0 {
81			// Skip blank lines.
82			continue
83		}
84
85		// Each line is a name and a nid, separated by space.
86		if len(fields) != 2 {
87			return nil, 0, withLine(errors.New("syntax error"))
88		}
89		name := fields[0]
90		nid, err := strconv.Atoi(fields[1])
91		if err != nil {
92			return nil, 0, withLine(err)
93		}
94		if nid < 0 {
95			return nil, 0, withLine(errors.New("invalid NID"))
96		}
97
98		// NID_undef is implicitly defined.
99		if name == "undef" && nid == 0 {
100			continue
101		}
102
103		// Forbid duplicates.
104		if _, ok := nameToNID[name]; ok {
105			return nil, 0, withLine(fmt.Errorf("duplicate name %q", name))
106		}
107		if _, ok := nidsSeen[nid]; ok {
108			return nil, 0, withLine(fmt.Errorf("duplicate NID %d", nid))
109		}
110
111		nameToNID[name] = nid
112		nidsSeen[nid] = struct{}{}
113
114		if nid >= numNIDs {
115			numNIDs = nid + 1
116		}
117	}
118	if err := scanner.Err(); err != nil {
119		return nil, 0, fmt.Errorf("error reading %s: %s", path, err)
120	}
121
122	return nameToNID, numNIDs, nil
123}
124
125func parseOID(aliases map[string][]int, in []string) (oid []int, err error) {
126	if len(in) == 0 {
127		return
128	}
129
130	// The first entry may be a reference to a previous alias.
131	if alias, ok := aliases[sanitizeName(in[0])]; ok {
132		in = in[1:]
133		oid = append(oid, alias...)
134	}
135
136	for _, c := range in {
137		val, err := strconv.Atoi(c)
138		if err != nil {
139			return nil, err
140		}
141		if val < 0 {
142			return nil, fmt.Errorf("negative component")
143		}
144		oid = append(oid, val)
145	}
146	return
147}
148
149func appendBase128(dst []byte, value int) []byte {
150	// Zero is encoded with one, not zero bytes.
151	if value == 0 {
152		return append(dst, 0)
153	}
154
155	// Count how many bytes are needed.
156	var l int
157	for n := value; n != 0; n >>= 7 {
158		l++
159	}
160	for ; l > 0; l-- {
161		b := byte(value>>uint(7*(l-1))) & 0x7f
162		if l > 1 {
163			b |= 0x80
164		}
165		dst = append(dst, b)
166	}
167	return dst
168}
169
170func encodeOID(oid []int) []byte {
171	if len(oid) < 2 {
172		return nil
173	}
174
175	var der []byte
176	der = appendBase128(der, 40*oid[0]+oid[1])
177	for _, value := range oid[2:] {
178		der = appendBase128(der, value)
179	}
180	return der
181}
182
183func readObjects(numPath, objectsPath string) (*objects, error) {
184	nameToNID, numNIDs, err := readNumbers(numPath)
185	if err != nil {
186		return nil, err
187	}
188
189	in, err := os.Open(objectsPath)
190	if err != nil {
191		return nil, err
192	}
193	defer in.Close()
194
195	// Implicitly define NID_undef.
196	objs := &objects{
197		byNID:     make([]object, numNIDs),
198		nameToNID: make(map[string]int),
199	}
200
201	objs.byNID[0] = object{
202		name:         "undef",
203		shortName:    "UNDEF",
204		longName:     "undefined",
205		hasShortName: true,
206		hasLongName:  true,
207	}
208	objs.nameToNID["undef"] = 0
209
210	var module, nextName string
211	var lineNo int
212	longNamesSeen := make(map[string]struct{})
213	shortNamesSeen := make(map[string]struct{})
214	aliases := make(map[string][]int)
215	scanner := bufio.NewScanner(in)
216	for scanner.Scan() {
217		line := scanner.Text()
218		lineNo++
219		withLine := func(err error) error {
220			return fmt.Errorf("%s:%d: %s", objectsPath, lineNo, err)
221		}
222
223		// Remove comments.
224		idx := strings.IndexRune(line, '#')
225		if idx >= 0 {
226			line = line[:idx]
227		}
228
229		// Skip empty lines.
230		line = strings.TrimSpace(line)
231		if len(line) == 0 {
232			continue
233		}
234
235		if line[0] == '!' {
236			args := strings.Fields(line)
237			switch args[0] {
238			case "!module":
239				if len(args) != 2 {
240					return nil, withLine(errors.New("too many arguments"))
241				}
242				module = sanitizeName(args[1]) + "_"
243			case "!global":
244				module = ""
245			case "!Cname":
246				// !Cname directives override the name for the
247				// next object.
248				if len(args) != 2 {
249					return nil, withLine(errors.New("too many arguments"))
250				}
251				nextName = sanitizeName(args[1])
252			case "!Alias":
253				// !Alias directives define an alias for an OID
254				// without emitting an object.
255				if len(nextName) != 0 {
256					return nil, withLine(errors.New("!Cname directives may not modify !Alias directives."))
257				}
258				if len(args) < 3 {
259					return nil, withLine(errors.New("not enough arguments"))
260				}
261				aliasName := module + sanitizeName(args[1])
262				oid, err := parseOID(aliases, args[2:])
263				if err != nil {
264					return nil, withLine(err)
265				}
266				if _, ok := aliases[aliasName]; ok {
267					return nil, withLine(fmt.Errorf("duplicate name '%s'", aliasName))
268				}
269				aliases[aliasName] = oid
270			default:
271				return nil, withLine(fmt.Errorf("unknown directive '%s'", args[0]))
272			}
273			continue
274		}
275
276		fields := strings.Split(line, ":")
277		if len(fields) < 2 || len(fields) > 3 {
278			return nil, withLine(errors.New("invalid field count"))
279		}
280
281		obj := object{name: nextName}
282		nextName = ""
283
284		var err error
285		obj.oid, err = parseOID(aliases, strings.Fields(fields[0]))
286		if err != nil {
287			return nil, withLine(err)
288		}
289		obj.encoded = encodeOID(obj.oid)
290
291		obj.shortName = strings.TrimSpace(fields[1])
292		if len(fields) == 3 {
293			obj.longName = strings.TrimSpace(fields[2])
294		}
295
296		// Long and short names default to each other if missing.
297		if len(obj.shortName) == 0 {
298			obj.shortName = obj.longName
299		} else {
300			obj.hasShortName = true
301		}
302		if len(obj.longName) == 0 {
303			obj.longName = obj.shortName
304		} else {
305			obj.hasLongName = true
306		}
307		if len(obj.shortName) == 0 || len(obj.longName) == 0 {
308			return nil, withLine(errors.New("object with no name"))
309		}
310
311		// If not already specified, prefer the long name if it has no
312		// spaces, otherwise the short name.
313		if len(obj.name) == 0 && strings.IndexRune(obj.longName, ' ') < 0 {
314			obj.name = sanitizeName(obj.longName)
315		}
316		if len(obj.name) == 0 {
317			obj.name = sanitizeName(obj.shortName)
318		}
319		obj.name = module + obj.name
320
321		// Check for duplicate names.
322		if _, ok := aliases[obj.name]; ok {
323			return nil, withLine(fmt.Errorf("duplicate name '%s'", obj.name))
324		}
325		if _, ok := shortNamesSeen[obj.shortName]; ok && len(obj.shortName) > 0 {
326			return nil, withLine(fmt.Errorf("duplicate short name '%s'", obj.shortName))
327		}
328		if _, ok := longNamesSeen[obj.longName]; ok && len(obj.longName) > 0 {
329			return nil, withLine(fmt.Errorf("duplicate long name '%s'", obj.longName))
330		}
331
332		// Allocate a NID.
333		nid, ok := nameToNID[obj.name]
334		if !ok {
335			nid = len(objs.byNID)
336			objs.byNID = append(objs.byNID, object{})
337		}
338
339		objs.byNID[nid] = obj
340		objs.nameToNID[obj.name] = nid
341
342		longNamesSeen[obj.longName] = struct{}{}
343		shortNamesSeen[obj.shortName] = struct{}{}
344		aliases[obj.name] = obj.oid
345	}
346	if err := scanner.Err(); err != nil {
347		return nil, err
348	}
349
350	// The kNIDsIn*Order constants assume each NID fits in a uint16_t.
351	if len(objs.byNID) > 0xffff {
352		return nil, errors.New("too many NIDs allocated")
353	}
354
355	return objs, nil
356}
357
358func writeNumbers(path string, objs *objects) error {
359	out, err := os.Create(path)
360	if err != nil {
361		return err
362	}
363	defer out.Close()
364
365	for nid, obj := range objs.byNID {
366		if len(obj.name) == 0 {
367			continue
368		}
369		if _, err := fmt.Fprintf(out, "%s\t\t%d\n", obj.name, nid); err != nil {
370			return err
371		}
372	}
373	return nil
374}
375
376func clangFormat(input string) (string, error) {
377	var b bytes.Buffer
378	cmd := exec.Command("clang-format")
379	cmd.Stdin = strings.NewReader(input)
380	cmd.Stdout = &b
381	cmd.Stderr = os.Stderr
382	if err := cmd.Run(); err != nil {
383		return "", err
384	}
385	return b.String(), nil
386}
387
388func writeHeader(path string, objs *objects) error {
389	var b bytes.Buffer
390	fmt.Fprintf(&b, `/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
391 * All rights reserved.
392 *
393 * This package is an SSL implementation written
394 * by Eric Young (eay@cryptsoft.com).
395 * The implementation was written so as to conform with Netscapes SSL.
396 *
397 * This library is free for commercial and non-commercial use as long as
398 * the following conditions are aheared to.  The following conditions
399 * apply to all code found in this distribution, be it the RC4, RSA,
400 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
401 * included with this distribution is covered by the same copyright terms
402 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
403 *
404 * Copyright remains Eric Young's, and as such any Copyright notices in
405 * the code are not to be removed.
406 * If this package is used in a product, Eric Young should be given attribution
407 * as the author of the parts of the library used.
408 * This can be in the form of a textual message at program startup or
409 * in documentation (online or textual) provided with the package.
410 *
411 * Redistribution and use in source and binary forms, with or without
412 * modification, are permitted provided that the following conditions
413 * are met:
414 * 1. Redistributions of source code must retain the copyright
415 *    notice, this list of conditions and the following disclaimer.
416 * 2. Redistributions in binary form must reproduce the above copyright
417 *    notice, this list of conditions and the following disclaimer in the
418 *    documentation and/or other materials provided with the distribution.
419 * 3. All advertising materials mentioning features or use of this software
420 *    must display the following acknowledgement:
421 *    "This product includes cryptographic software written by
422 *     Eric Young (eay@cryptsoft.com)"
423 *    The word 'cryptographic' can be left out if the rouines from the library
424 *    being used are not cryptographic related :-).
425 * 4. If you include any Windows specific code (or a derivative thereof) from
426 *    the apps directory (application code) you must include an acknowledgement:
427 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
428 *
429 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG `+"``"+`AS IS'' AND
430 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
431 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
432 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
433 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
434 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
435 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
436 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
437 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
438 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
439 * SUCH DAMAGE.
440 *
441 * The licence and distribution terms for any publically available version or
442 * derivative of this code cannot be changed.  i.e. this code cannot simply be
443 * copied and put under another distribution licence
444 * [including the GNU Public Licence.] */
445
446/* This file is generated by crypto/obj/objects.go. */
447
448#ifndef OPENSSL_HEADER_NID_H
449#define OPENSSL_HEADER_NID_H
450
451#include <openssl/base.h>
452
453#if defined(__cplusplus)
454extern "C" {
455#endif
456
457
458/* The nid library provides numbered values for ASN.1 object identifiers and
459 * other symbols. These values are used by other libraries to identify
460 * cryptographic primitives.
461 *
462 * A separate objects library, obj.h, provides functions for converting between
463 * nids and object identifiers. However it depends on large internal tables with
464 * the encodings of every nid defined. Consumers concerned with binary size
465 * should instead embed the encodings of the few consumed OIDs and compare
466 * against those.
467 *
468 * These values should not be used outside of a single process; they are not
469 * stable identifiers. */
470
471
472`)
473
474	for nid, obj := range objs.byNID {
475		if len(obj.name) == 0 {
476			continue
477		}
478
479		if obj.hasShortName {
480			fmt.Fprintf(&b, "#define SN_%s \"%s\"\n", obj.name, obj.shortName)
481		}
482		if obj.hasLongName {
483			fmt.Fprintf(&b, "#define LN_%s \"%s\"\n", obj.name, obj.longName)
484		}
485		fmt.Fprintf(&b, "#define NID_%s %d\n", obj.name, nid)
486
487		// Although NID_undef does not have an OID, OpenSSL emits
488		// OBJ_undef as if it were zero.
489		oid := obj.oid
490		if nid == 0 {
491			oid = []int{0}
492		}
493		if len(oid) != 0 {
494			var oidStr string
495			for _, val := range oid {
496				if len(oidStr) != 0 {
497					oidStr += ","
498				}
499				oidStr += fmt.Sprintf("%dL", val)
500			}
501
502			fmt.Fprintf(&b, "#define OBJ_%s %s\n", obj.name, oidStr)
503		}
504
505		fmt.Fprintf(&b, "\n")
506	}
507
508	fmt.Fprintf(&b, `
509#if defined(__cplusplus)
510}  /* extern C */
511#endif
512
513#endif  /* OPENSSL_HEADER_NID_H */
514`)
515
516	formatted, err := clangFormat(b.String())
517	if err != nil {
518		return err
519	}
520
521	return ioutil.WriteFile(path, []byte(formatted), 0666)
522}
523
524// TODO(davidben): Replace this with sort.Slice once Go 1.8 is sufficiently
525// common.
526type nidSorter struct {
527	nids []int
528	objs *objects
529	cmp  func(a, b object) bool
530}
531
532func (a nidSorter) obj(i int) object   { return a.objs.byNID[a.nids[i]] }
533func (a nidSorter) Len() int           { return len(a.nids) }
534func (a nidSorter) Swap(i, j int)      { a.nids[i], a.nids[j] = a.nids[j], a.nids[i] }
535func (a nidSorter) Less(i, j int) bool { return a.cmp(a.obj(i), a.obj(j)) }
536
537func sortNIDs(nids []int, objs *objects, cmp func(a, b object) bool) {
538	sort.Sort(&nidSorter{nids, objs, cmp})
539}
540
541func writeData(path string, objs *objects) error {
542	var b bytes.Buffer
543	fmt.Fprintf(&b, `/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
544 * All rights reserved.
545 *
546 * This package is an SSL implementation written
547 * by Eric Young (eay@cryptsoft.com).
548 * The implementation was written so as to conform with Netscapes SSL.
549 *
550 * This library is free for commercial and non-commercial use as long as
551 * the following conditions are aheared to.  The following conditions
552 * apply to all code found in this distribution, be it the RC4, RSA,
553 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
554 * included with this distribution is covered by the same copyright terms
555 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
556 *
557 * Copyright remains Eric Young's, and as such any Copyright notices in
558 * the code are not to be removed.
559 * If this package is used in a product, Eric Young should be given attribution
560 * as the author of the parts of the library used.
561 * This can be in the form of a textual message at program startup or
562 * in documentation (online or textual) provided with the package.
563 *
564 * Redistribution and use in source and binary forms, with or without
565 * modification, are permitted provided that the following conditions
566 * are met:
567 * 1. Redistributions of source code must retain the copyright
568 *    notice, this list of conditions and the following disclaimer.
569 * 2. Redistributions in binary form must reproduce the above copyright
570 *    notice, this list of conditions and the following disclaimer in the
571 *    documentation and/or other materials provided with the distribution.
572 * 3. All advertising materials mentioning features or use of this software
573 *    must display the following acknowledgement:
574 *    "This product includes cryptographic software written by
575 *     Eric Young (eay@cryptsoft.com)"
576 *    The word 'cryptographic' can be left out if the rouines from the library
577 *    being used are not cryptographic related :-).
578 * 4. If you include any Windows specific code (or a derivative thereof) from
579 *    the apps directory (application code) you must include an acknowledgement:
580 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
581 *
582 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG `+"``"+`AS IS'' AND
583 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
584 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
585 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
586 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
587 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
588 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
589 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
590 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
591 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
592 * SUCH DAMAGE.
593 *
594 * The licence and distribution terms for any publically available version or
595 * derivative of this code cannot be changed.  i.e. this code cannot simply be
596 * copied and put under another distribution licence
597 * [including the GNU Public Licence.] */
598
599/* This file is generated by crypto/obj/objects.go. */
600
601
602`)
603
604	fmt.Fprintf(&b, "#define NUM_NID %d\n", len(objs.byNID))
605
606	// Emit each object's DER encoding, concatenated, and save the offsets.
607	fmt.Fprintf(&b, "\nstatic const uint8_t kObjectData[] = {\n")
608	offsets := make([]int, len(objs.byNID))
609	var nextOffset int
610	for nid, obj := range objs.byNID {
611		if len(obj.name) == 0 || len(obj.encoded) == 0 {
612			offsets[nid] = -1
613			continue
614		}
615
616		offsets[nid] = nextOffset
617		nextOffset += len(obj.encoded)
618		fmt.Fprintf(&b, "/* NID_%s */\n", obj.name)
619		for _, val := range obj.encoded {
620			fmt.Fprintf(&b, "0x%02x, ", val)
621		}
622		fmt.Fprintf(&b, "\n")
623	}
624	fmt.Fprintf(&b, "};\n")
625
626	// Emit an ASN1_OBJECT for each object.
627	fmt.Fprintf(&b, "\nstatic const ASN1_OBJECT kObjects[NUM_NID] = {\n")
628	for nid, obj := range objs.byNID {
629		if len(obj.name) == 0 {
630			fmt.Fprintf(&b, "{NULL, NULL, NID_undef, 0, NULL, 0},\n")
631			continue
632		}
633
634		fmt.Fprintf(&b, "{\"%s\", \"%s\", NID_%s, ", obj.shortName, obj.longName, obj.name)
635		if offset := offsets[nid]; offset >= 0 {
636			fmt.Fprintf(&b, "%d, &kObjectData[%d], 0},\n", len(obj.encoded), offset)
637		} else {
638			fmt.Fprintf(&b, "0, NULL, 0},\n")
639		}
640	}
641	fmt.Fprintf(&b, "};\n")
642
643	// Emit a list of NIDs sorted by short name.
644	var nids []int
645	for nid, obj := range objs.byNID {
646		if len(obj.name) == 0 || len(obj.shortName) == 0 {
647			continue
648		}
649		nids = append(nids, nid)
650	}
651	sortNIDs(nids, objs, func(a, b object) bool { return a.shortName < b.shortName })
652
653	fmt.Fprintf(&b, "\nstatic const uint16_t kNIDsInShortNameOrder[] = {\n")
654	for _, nid := range nids {
655		fmt.Fprintf(&b, "%d /* %s */,\n", nid, objs.byNID[nid].shortName)
656	}
657	fmt.Fprintf(&b, "};\n")
658
659	// Emit a list of NIDs sorted by long name.
660	nids = nil
661	for nid, obj := range objs.byNID {
662		if len(obj.name) == 0 || len(obj.longName) == 0 {
663			continue
664		}
665		nids = append(nids, nid)
666	}
667	sortNIDs(nids, objs, func(a, b object) bool { return a.longName < b.longName })
668
669	fmt.Fprintf(&b, "\nstatic const uint16_t kNIDsInLongNameOrder[] = {\n")
670	for _, nid := range nids {
671		fmt.Fprintf(&b, "%d /* %s */,\n", nid, objs.byNID[nid].longName)
672	}
673	fmt.Fprintf(&b, "};\n")
674
675	// Emit a list of NIDs sorted by OID.
676	nids = nil
677	for nid, obj := range objs.byNID {
678		if len(obj.name) == 0 || len(obj.encoded) == 0 {
679			continue
680		}
681		nids = append(nids, nid)
682	}
683	sortNIDs(nids, objs, func(a, b object) bool {
684		// This comparison must match the definition of |obj_cmp|.
685		if len(a.encoded) < len(b.encoded) {
686			return true
687		}
688		if len(a.encoded) > len(b.encoded) {
689			return false
690		}
691		return bytes.Compare(a.encoded, b.encoded) < 0
692	})
693
694	fmt.Fprintf(&b, "\nstatic const uint16_t kNIDsInOIDOrder[] = {\n")
695	for _, nid := range nids {
696		obj := objs.byNID[nid]
697		fmt.Fprintf(&b, "%d /* ", nid)
698		for i, c := range obj.oid {
699			if i > 0 {
700				fmt.Fprintf(&b, ".")
701			}
702			fmt.Fprintf(&b, "%d", c)
703		}
704		fmt.Fprintf(&b, " (OBJ_%s) */,\n", obj.name)
705	}
706	fmt.Fprintf(&b, "};\n")
707
708	formatted, err := clangFormat(b.String())
709	if err != nil {
710		return err
711	}
712
713	return ioutil.WriteFile(path, []byte(formatted), 0666)
714}
715
716func main() {
717	objs, err := readObjects("obj_mac.num", "objects.txt")
718	if err != nil {
719		fmt.Fprintf(os.Stderr, "Error reading objects: %s\n", err)
720		os.Exit(1)
721	}
722
723	if err := writeNumbers("obj_mac.num", objs); err != nil {
724		fmt.Fprintf(os.Stderr, "Error writing numbers: %s\n", err)
725		os.Exit(1)
726	}
727
728	if err := writeHeader("../../include/openssl/nid.h", objs); err != nil {
729		fmt.Fprintf(os.Stderr, "Error writing header: %s\n", err)
730		os.Exit(1)
731	}
732
733	if err := writeData("obj_dat.h", objs); err != nil {
734		fmt.Fprintf(os.Stderr, "Error writing data: %s\n", err)
735		os.Exit(1)
736	}
737}
738