Packages
hackney
2.0.0-beta.1
4.7.2
4.7.1
4.7.0
4.6.1
4.6.0
4.5.2
4.5.1
4.5.0
4.4.5
4.4.3
4.4.2
4.4.1
4.4.0
4.3.0
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.3
4.0.2
4.0.1
4.0.0
3.2.1
3.2.0
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
retired
2.0.1
2.0.0
2.0.0-beta.1
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.0
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.0
1.13.0
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.0
1.7.1
1.7.0
1.6.6
retired
1.6.5
1.6.4
retired
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.6
1.0.5
1.0.2
1.0.1
0.15.2
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
Simple HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
c_src/boringssl/crypto/obj/objects.go
// Copyright 2016 The BoringSSL Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build ignore
package main
import (
"bufio"
"bytes"
"encoding/asn1"
"errors"
"fmt"
"os"
"os/exec"
"sort"
"strconv"
"strings"
)
func sanitizeName(in string) string {
in = strings.Replace(in, "-", "_", -1)
in = strings.Replace(in, ".", "_", -1)
in = strings.Replace(in, " ", "_", -1)
return in
}
type object struct {
name string
// shortName and longName are the short and long names, respectively. If
// one is missing, it takes the value of the other, but the
// corresponding SN_foo or LN_foo macro is not defined.
shortName, longName string
hasShortName, hasLongName bool
oid asn1.ObjectIdentifier
encoded []byte
}
type objects struct {
// byNID is the list of all objects, indexed by nid.
byNID []object
// nameToNID is a map from object name to nid.
nameToNID map[string]int
}
func readNumbers(path string) (nameToNID map[string]int, numNIDs int, err error) {
in, err := os.Open(path)
if err != nil {
return nil, 0, err
}
defer in.Close()
nameToNID = make(map[string]int)
nidsSeen := make(map[int]struct{})
// Reserve NID 0 for NID_undef.
numNIDs = 1
nameToNID["undef"] = 0
nidsSeen[0] = struct{}{}
var lineNo int
scanner := bufio.NewScanner(in)
for scanner.Scan() {
line := scanner.Text()
lineNo++
withLine := func(err error) error {
return fmt.Errorf("%s:%d: %s", path, lineNo, err)
}
fields := strings.Fields(line)
if len(fields) == 0 {
// Skip blank lines.
continue
}
// Each line is a name and a nid, separated by space.
if len(fields) != 2 {
return nil, 0, withLine(errors.New("syntax error"))
}
name := fields[0]
nid, err := strconv.Atoi(fields[1])
if err != nil {
return nil, 0, withLine(err)
}
if nid < 0 {
return nil, 0, withLine(errors.New("invalid NID"))
}
// NID_undef is implicitly defined.
if name == "undef" && nid == 0 {
continue
}
// Forbid duplicates.
if _, ok := nameToNID[name]; ok {
return nil, 0, withLine(fmt.Errorf("duplicate name %q", name))
}
if _, ok := nidsSeen[nid]; ok {
return nil, 0, withLine(fmt.Errorf("duplicate NID %d", nid))
}
nameToNID[name] = nid
nidsSeen[nid] = struct{}{}
if nid >= numNIDs {
numNIDs = nid + 1
}
}
if err := scanner.Err(); err != nil {
return nil, 0, fmt.Errorf("error reading %s: %s", path, err)
}
return nameToNID, numNIDs, nil
}
func parseOID(aliases map[string]asn1.ObjectIdentifier, in []string) (oid asn1.ObjectIdentifier, err error) {
if len(in) == 0 {
return
}
// The first entry may be a reference to a previous alias.
if alias, ok := aliases[sanitizeName(in[0])]; ok {
in = in[1:]
oid = append(oid, alias...)
}
for _, c := range in {
val, err := strconv.Atoi(c)
if err != nil {
return nil, err
}
if val < 0 {
return nil, fmt.Errorf("negative component")
}
oid = append(oid, val)
}
return
}
func appendBase128(dst []byte, value int) []byte {
// Zero is encoded with one, not zero bytes.
if value == 0 {
return append(dst, 0)
}
// Count how many bytes are needed.
var l int
for n := value; n != 0; n >>= 7 {
l++
}
for ; l > 0; l-- {
b := byte(value>>uint(7*(l-1))) & 0x7f
if l > 1 {
b |= 0x80
}
dst = append(dst, b)
}
return dst
}
func encodeOID(oid []int) []byte {
if len(oid) < 2 {
return nil
}
var der []byte
der = appendBase128(der, 40*oid[0]+oid[1])
for _, value := range oid[2:] {
der = appendBase128(der, value)
}
return der
}
func readObjects(numPath, objectsPath string) (*objects, error) {
nameToNID, numNIDs, err := readNumbers(numPath)
if err != nil {
return nil, err
}
in, err := os.Open(objectsPath)
if err != nil {
return nil, err
}
defer in.Close()
// Implicitly define NID_undef.
objs := &objects{
byNID: make([]object, numNIDs),
nameToNID: make(map[string]int),
}
objs.byNID[0] = object{
name: "undef",
shortName: "UNDEF",
longName: "undefined",
hasShortName: true,
hasLongName: true,
}
objs.nameToNID["undef"] = 0
var module, nextName string
var lineNo int
longNamesSeen := make(map[string]struct{})
shortNamesSeen := make(map[string]struct{})
aliases := make(map[string]asn1.ObjectIdentifier)
scanner := bufio.NewScanner(in)
for scanner.Scan() {
line := scanner.Text()
lineNo++
withLine := func(err error) error {
return fmt.Errorf("%s:%d: %s", objectsPath, lineNo, err)
}
// Remove comments.
idx := strings.IndexRune(line, '#')
if idx >= 0 {
line = line[:idx]
}
// Skip empty lines.
line = strings.TrimSpace(line)
if len(line) == 0 {
continue
}
if line[0] == '!' {
args := strings.Fields(line)
switch args[0] {
case "!module":
if len(args) != 2 {
return nil, withLine(errors.New("too many arguments"))
}
module = sanitizeName(args[1]) + "_"
case "!global":
module = ""
case "!Cname":
// !Cname directives override the name for the
// next object.
if len(args) != 2 {
return nil, withLine(errors.New("too many arguments"))
}
nextName = sanitizeName(args[1])
case "!Alias":
// !Alias directives define an alias for an OID
// without emitting an object.
if len(nextName) != 0 {
return nil, withLine(errors.New("!Cname directives may not modify !Alias directives."))
}
if len(args) < 3 {
return nil, withLine(errors.New("not enough arguments"))
}
aliasName := module + sanitizeName(args[1])
oid, err := parseOID(aliases, args[2:])
if err != nil {
return nil, withLine(err)
}
if _, ok := aliases[aliasName]; ok {
return nil, withLine(fmt.Errorf("duplicate name '%s'", aliasName))
}
aliases[aliasName] = oid
default:
return nil, withLine(fmt.Errorf("unknown directive '%s'", args[0]))
}
continue
}
fields := strings.Split(line, ":")
if len(fields) < 2 || len(fields) > 3 {
return nil, withLine(errors.New("invalid field count"))
}
obj := object{name: nextName}
nextName = ""
var err error
obj.oid, err = parseOID(aliases, strings.Fields(fields[0]))
if err != nil {
return nil, withLine(err)
}
obj.encoded = encodeOID(obj.oid)
obj.shortName = strings.TrimSpace(fields[1])
if len(fields) == 3 {
obj.longName = strings.TrimSpace(fields[2])
}
// Long and short names default to each other if missing.
if len(obj.shortName) == 0 {
obj.shortName = obj.longName
} else {
obj.hasShortName = true
}
if len(obj.longName) == 0 {
obj.longName = obj.shortName
} else {
obj.hasLongName = true
}
if len(obj.shortName) == 0 || len(obj.longName) == 0 {
return nil, withLine(errors.New("object with no name"))
}
// If not already specified, prefer the long name if it has no
// spaces, otherwise the short name.
if len(obj.name) == 0 && strings.IndexRune(obj.longName, ' ') < 0 {
obj.name = sanitizeName(obj.longName)
}
if len(obj.name) == 0 {
obj.name = sanitizeName(obj.shortName)
}
obj.name = module + obj.name
// Check for duplicate names.
if _, ok := aliases[obj.name]; ok {
return nil, withLine(fmt.Errorf("duplicate name '%s'", obj.name))
}
if _, ok := shortNamesSeen[obj.shortName]; ok && len(obj.shortName) > 0 {
return nil, withLine(fmt.Errorf("duplicate short name '%s'", obj.shortName))
}
if _, ok := longNamesSeen[obj.longName]; ok && len(obj.longName) > 0 {
return nil, withLine(fmt.Errorf("duplicate long name '%s'", obj.longName))
}
// Allocate a NID.
nid, ok := nameToNID[obj.name]
if !ok {
nid = len(objs.byNID)
objs.byNID = append(objs.byNID, object{})
}
objs.byNID[nid] = obj
objs.nameToNID[obj.name] = nid
longNamesSeen[obj.longName] = struct{}{}
shortNamesSeen[obj.shortName] = struct{}{}
aliases[obj.name] = obj.oid
}
if err := scanner.Err(); err != nil {
return nil, err
}
// The kNIDsIn*Order constants assume each NID fits in a uint16_t.
if len(objs.byNID) > 0xffff {
return nil, errors.New("too many NIDs allocated")
}
return objs, nil
}
func writeNumbers(path string, objs *objects) error {
out, err := os.Create(path)
if err != nil {
return err
}
defer out.Close()
for nid, obj := range objs.byNID {
if len(obj.name) == 0 {
continue
}
if _, err := fmt.Fprintf(out, "%s\t\t%d\n", obj.name, nid); err != nil {
return err
}
}
return nil
}
func clangFormat(input string) (string, error) {
var b bytes.Buffer
cmd := exec.Command("clang-format")
cmd.Stdin = strings.NewReader(input)
cmd.Stdout = &b
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return "", err
}
return b.String(), nil
}
func writeHeader(path string, objs *objects) error {
var b bytes.Buffer
fmt.Fprintf(&b, `// Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This file is generated by crypto/obj/objects.go.
#ifndef OPENSSL_HEADER_NID_H
#define OPENSSL_HEADER_NID_H
#include <openssl/base.h> // IWYU pragma: export
#if defined(__cplusplus)
extern "C" {
#endif
// The nid library provides numbered values for ASN.1 object identifiers and
// other symbols. These values are used by other libraries to identify
// cryptographic primitives.
//
// A separate objects library, obj.h, provides functions for converting between
// nids and object identifiers. However it depends on large internal tables with
// the encodings of every nid defined. Consumers concerned with binary size
// should instead embed the encodings of the few consumed OIDs and compare
// against those.
//
// Constants are defined as follows:
//
// - NID_foo is the integer NID of foo.
// - SN_foo is the "short name" of foo, omitted if there is no short name.
// - LN_foo is the "long name" of foo, omitted if there is no long name.
// - OBJ_foo expands to a comma-separated sequence of integers for foo's OID,
// omitted if foo has no OID.
// - OBJ_ENC_foo expands to a comma-separated sequence of bytes for foo's OID
// encoded in DER, excluding the tag and length. This is omitted if foo has
// no OID.
//
// NID values should not be used outside of a single process; they are not
// stable identifiers.
`)
for nid, obj := range objs.byNID {
if len(obj.name) == 0 {
continue
}
if obj.hasShortName {
fmt.Fprintf(&b, "#define SN_%s \"%s\"\n", obj.name, obj.shortName)
}
if obj.hasLongName {
fmt.Fprintf(&b, "#define LN_%s \"%s\"\n", obj.name, obj.longName)
}
fmt.Fprintf(&b, "#define NID_%s %d\n", obj.name, nid)
// Although NID_undef does not have an OID, OpenSSL emits
// OBJ_undef as if it were zero.
oid := obj.oid
if nid == 0 {
oid = asn1.ObjectIdentifier{0}
}
if len(oid) != 0 {
var oidStr strings.Builder
for _, val := range oid {
if oidStr.Len() != 0 {
oidStr.WriteString(", ")
}
fmt.Fprintf(&oidStr, "%dL", val)
}
fmt.Fprintf(&b, "#define OBJ_%s %s\n", obj.name, oidStr.String())
}
// Some NIDs refer to the top-level OID arcs, which cannot be encoded
// as OIDs. (The encoding can only represent two or more components.)
if len(oid) > 1 {
var oidEncStr strings.Builder
for _, val := range encodeOID(oid) {
if oidEncStr.Len() != 0 {
oidEncStr.WriteString(", ")
}
fmt.Fprintf(&oidEncStr, "0x%02x", val)
}
fmt.Fprintf(&b, "#define OBJ_ENC_%s %s\n", obj.name, oidEncStr.String())
}
fmt.Fprintf(&b, "\n")
}
fmt.Fprintf(&b, `
#if defined(__cplusplus)
} /* extern C */
#endif
#endif /* OPENSSL_HEADER_NID_H */
`)
formatted, err := clangFormat(b.String())
if err != nil {
return err
}
return os.WriteFile(path, []byte(formatted), 0666)
}
func sortNIDs(nids []int, objs *objects, cmp func(a, b object) bool) {
sort.Slice(nids, func(i, j int) bool { return cmp(objs.byNID[nids[i]], objs.byNID[nids[j]]) })
}
func writeData(path string, objs *objects) error {
var b bytes.Buffer
fmt.Fprintf(&b, `// Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This file is generated by crypto/obj/objects.go.
`)
fmt.Fprintf(&b, "#define NUM_NID %d\n", len(objs.byNID))
// Emit each object's DER encoding, concatenated, and save the offsets.
fmt.Fprintf(&b, "\nstatic const uint8_t kObjectData[] = {\n")
offsets := make([]int, len(objs.byNID))
var nextOffset int
for nid, obj := range objs.byNID {
if len(obj.name) == 0 || len(obj.encoded) == 0 {
offsets[nid] = -1
continue
}
offsets[nid] = nextOffset
nextOffset += len(obj.encoded)
fmt.Fprintf(&b, "/* NID_%s */\n", obj.name)
for _, val := range obj.encoded {
fmt.Fprintf(&b, "0x%02x, ", val)
}
fmt.Fprintf(&b, "\n")
}
fmt.Fprintf(&b, "};\n")
// Emit an ASN1_OBJECT for each object.
fmt.Fprintf(&b, "\nstatic const ASN1_OBJECT kObjects[NUM_NID] = {\n")
for nid, obj := range objs.byNID {
// Skip the entry for NID_undef. It is stored separately, so that
// OBJ_get_undef avoids pulling in the table.
if nid == 0 {
continue
}
if len(obj.name) == 0 {
fmt.Fprintf(&b, "{NULL, NULL, NID_undef, 0, NULL, 0},\n")
continue
}
fmt.Fprintf(&b, "{\"%s\", \"%s\", NID_%s, ", obj.shortName, obj.longName, obj.name)
if offset := offsets[nid]; offset >= 0 {
fmt.Fprintf(&b, "%d, &kObjectData[%d], 0},\n", len(obj.encoded), offset)
} else {
fmt.Fprintf(&b, "0, NULL, 0},\n")
}
}
fmt.Fprintf(&b, "};\n")
// Emit a list of NIDs sorted by short name.
var nids []int
for nid, obj := range objs.byNID {
if len(obj.name) == 0 || len(obj.shortName) == 0 {
continue
}
nids = append(nids, nid)
}
sortNIDs(nids, objs, func(a, b object) bool { return a.shortName < b.shortName })
fmt.Fprintf(&b, "\nstatic const uint16_t kNIDsInShortNameOrder[] = {\n")
for _, nid := range nids {
// Including NID_undef in the table does not do anything. Whether OBJ_sn2nid
// finds the object or not, it will return NID_undef.
if nid != 0 {
fmt.Fprintf(&b, "%d /* %s */,\n", nid, objs.byNID[nid].shortName)
}
}
fmt.Fprintf(&b, "};\n")
// Emit a list of NIDs sorted by long name.
nids = nil
for nid, obj := range objs.byNID {
if len(obj.name) == 0 || len(obj.longName) == 0 {
continue
}
nids = append(nids, nid)
}
sortNIDs(nids, objs, func(a, b object) bool { return a.longName < b.longName })
fmt.Fprintf(&b, "\nstatic const uint16_t kNIDsInLongNameOrder[] = {\n")
for _, nid := range nids {
// Including NID_undef in the table does not do anything. Whether OBJ_ln2nid
// finds the object or not, it will return NID_undef.
if nid != 0 {
fmt.Fprintf(&b, "%d /* %s */,\n", nid, objs.byNID[nid].longName)
}
}
fmt.Fprintf(&b, "};\n")
// Emit a list of NIDs sorted by OID.
nids = nil
for nid, obj := range objs.byNID {
if len(obj.name) == 0 || len(obj.encoded) == 0 {
continue
}
nids = append(nids, nid)
}
sortNIDs(nids, objs, func(a, b object) bool {
// This comparison must match the definition of |obj_cmp|.
if len(a.encoded) < len(b.encoded) {
return true
}
if len(a.encoded) > len(b.encoded) {
return false
}
return bytes.Compare(a.encoded, b.encoded) < 0
})
fmt.Fprintf(&b, "\nstatic const uint16_t kNIDsInOIDOrder[] = {\n")
for _, nid := range nids {
obj := objs.byNID[nid]
fmt.Fprintf(&b, "%d /* ", nid)
for i, c := range obj.oid {
if i > 0 {
fmt.Fprintf(&b, ".")
}
fmt.Fprintf(&b, "%d", c)
}
fmt.Fprintf(&b, " (OBJ_%s) */,\n", obj.name)
}
fmt.Fprintf(&b, "};\n")
formatted, err := clangFormat(b.String())
if err != nil {
return err
}
return os.WriteFile(path, []byte(formatted), 0666)
}
func main() {
objs, err := readObjects("obj_mac.num", "objects.txt")
if err != nil {
fmt.Fprintf(os.Stderr, "Error reading objects: %s\n", err)
os.Exit(1)
}
if err := writeNumbers("obj_mac.num", objs); err != nil {
fmt.Fprintf(os.Stderr, "Error writing numbers: %s\n", err)
os.Exit(1)
}
if err := writeHeader("../../include/openssl/nid.h", objs); err != nil {
fmt.Fprintf(os.Stderr, "Error writing header: %s\n", err)
os.Exit(1)
}
if err := writeData("obj_dat.h", objs); err != nil {
fmt.Fprintf(os.Stderr, "Error writing data: %s\n", err)
os.Exit(1)
}
}