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