github.com/zmap/zcrypto@v0.0.0-20240512203510-0fef58d9a9db/x509/extended_key_usage_gen.go (about)

     1  // The following directive is necessary to make the package coherent:
     2  
     3  //go:build ignore
     4  // +build ignore
     5  
     6  // This program generates extended_key_usage.go. It can be invoked by running
     7  // `$ go generate`
     8  package main
     9  
    10  import (
    11  	"bytes"
    12  	"encoding/csv"
    13  	"io"
    14  	"net/http"
    15  	"os"
    16  	"sort"
    17  	"strings"
    18  )
    19  
    20  const (
    21  	COLUMN_IDX_OID        = 0
    22  	COLUMN_IDX_SHORT_NAME = 2
    23  )
    24  
    25  const (
    26  	GO_PREFIX    = "oidExtKeyUsage"
    27  	CONST_PREFIX = "OID_EKU"
    28  )
    29  
    30  type OID struct {
    31  	OID       string
    32  	ShortName string
    33  }
    34  
    35  func (o *OID) OIDDecl() string {
    36  	parts := strings.Split(o.OID, ".")
    37  	buffer := bytes.Buffer{}
    38  	buffer.WriteString("asn1.ObjectIdentifier{")
    39  	for idx, p := range parts {
    40  		buffer.WriteString(p)
    41  		if idx != len(parts)-1 {
    42  			buffer.WriteString(", ")
    43  		}
    44  	}
    45  	buffer.WriteString("}")
    46  	return buffer.String()
    47  }
    48  
    49  func (o *OID) GoName(prefix string) string {
    50  	parts := strings.Split(o.ShortName, "-")
    51  	for idx, p := range parts {
    52  		if prefix == "" && idx == 0 {
    53  			continue
    54  		}
    55  		parts[idx] = strings.Title(p)
    56  	}
    57  	return prefix + strings.Join(parts, "")
    58  }
    59  
    60  func (o *OID) GoConstant(prefix string) string {
    61  	parts := strings.Split(o.ShortName, "-")
    62  	buffer := bytes.Buffer{}
    63  	if prefix != "" {
    64  		buffer.WriteString(strings.ToUpper(prefix))
    65  		buffer.WriteString("_")
    66  	}
    67  	for idx, p := range parts {
    68  		buffer.WriteString(strings.ToUpper(p))
    69  		if idx != len(parts)-1 {
    70  			buffer.WriteString("_")
    71  		}
    72  	}
    73  	return buffer.String()
    74  }
    75  
    76  func (o *OID) JSONName(prefix string) string {
    77  	parts := strings.Split(o.ShortName, "-")
    78  	buffer := bytes.Buffer{}
    79  	if prefix != "" {
    80  		buffer.WriteString(strings.ToLower(prefix))
    81  		buffer.WriteString("_")
    82  	}
    83  	for idx, p := range parts {
    84  		buffer.WriteString(strings.ToLower(p))
    85  		if idx != len(parts)-1 {
    86  			buffer.WriteString("_")
    87  		}
    88  	}
    89  	return buffer.String()
    90  }
    91  
    92  func (o *OID) StructFieldName() string {
    93  	parts := strings.Split(o.ShortName, "-")
    94  	buffer := bytes.Buffer{}
    95  	for _, p := range parts {
    96  		buffer.WriteString(strings.Title(p))
    97  	}
    98  	return buffer.String()
    99  }
   100  
   101  func writeHeader(out io.Writer) {
   102  	s := `// Created by extended_key_usage_gen; DO NOT EDIT
   103  
   104  // Copyright 2017 The Go Authors. All rights reserved.
   105  // Use of this source code is governed by a BSD-style
   106  // license that can be found in the LICENSE file.
   107  
   108  package x509
   109  
   110  import (
   111  	"encoding/asn1"
   112  )
   113  
   114  `
   115  	out.Write([]byte(s))
   116  }
   117  
   118  func generateASN1(rawToOID map[string]OID) []byte {
   119  	buffer := bytes.Buffer{}
   120  	// Create sorted slice of keys to ensure deterministic output
   121  	var keys = make([]string, 0, len(rawToOID))
   122  	for k := range rawToOID {
   123  		keys = append(keys, k)
   124  	}
   125  	sort.Strings(keys)
   126  	for _, k := range keys {
   127  		oid := rawToOID[k]
   128  		goName := oid.GoName(GO_PREFIX)
   129  		oidDecl := oid.OIDDecl()
   130  		buffer.WriteString(goName)
   131  		buffer.WriteString(" = ")
   132  		buffer.WriteString(oidDecl)
   133  		buffer.WriteString("\n")
   134  	}
   135  	return buffer.Bytes()
   136  }
   137  
   138  func generateIntegerConstants(rawToOID map[string]OID) []byte {
   139  	buffer := bytes.Buffer{}
   140  	buffer.WriteString("const (\n")
   141  	first := true
   142  	// Create sorted slice of keys to ensure deterministic output
   143  	var keys = make([]string, 0, len(rawToOID))
   144  	for k := range rawToOID {
   145  		keys = append(keys, k)
   146  	}
   147  	sort.Strings(keys)
   148  	for _, k := range keys {
   149  		oid := rawToOID[k]
   150  		goName := oid.GoName("ExtKeyUsage")
   151  		buffer.WriteString(goName)
   152  		if first {
   153  			buffer.WriteString(" ExtKeyUsage = iota")
   154  			first = false
   155  		}
   156  		buffer.WriteString("\n")
   157  	}
   158  	buffer.WriteString(")\n")
   159  	return buffer.Bytes()
   160  }
   161  
   162  func generateNameConstants(rawToOID map[string]OID) []byte {
   163  	buffer := bytes.Buffer{}
   164  	// Create sorted slice of keys to ensure deterministic output
   165  	var keys = make([]string, 0, len(rawToOID))
   166  	for k := range rawToOID {
   167  		keys = append(keys, k)
   168  	}
   169  	sort.Strings(keys)
   170  	for _, k := range keys {
   171  		oid := rawToOID[k]
   172  		constantName := oid.GoConstant(CONST_PREFIX)
   173  		buffer.WriteString(constantName)
   174  		buffer.WriteString(" = \"")
   175  		buffer.WriteString(oid.OID)
   176  		buffer.WriteString("\"\n")
   177  	}
   178  	return buffer.Bytes()
   179  }
   180  
   181  func generateOIDMap(rawToOID map[string]OID, mapName string) []byte {
   182  	buffer := bytes.Buffer{}
   183  	buffer.WriteString(mapName)
   184  	buffer.WriteString(" = make(map[string]asn1.ObjectIdentifier)\n")
   185  
   186  	// Create sorted slice of keys to ensure deterministic output
   187  	var keys = make([]string, 0, len(rawToOID))
   188  	for k := range rawToOID {
   189  		keys = append(keys, k)
   190  	}
   191  	sort.Strings(keys)
   192  	for _, k := range keys {
   193  		oid := rawToOID[k]
   194  		constantName := oid.GoConstant(CONST_PREFIX)
   195  		goName := oid.GoName(GO_PREFIX)
   196  		buffer.WriteString(mapName)
   197  		buffer.WriteString("[")
   198  		buffer.WriteString(constantName)
   199  		buffer.WriteString("] = ")
   200  		buffer.WriteString(goName)
   201  		buffer.WriteString("\n")
   202  	}
   203  	return buffer.Bytes()
   204  }
   205  
   206  func generateIntegerMap(rawToOID map[string]OID, mapName string) []byte {
   207  	buffer := bytes.Buffer{}
   208  	buffer.WriteString(mapName)
   209  	buffer.WriteString(" = make(map[string]ExtKeyUsage)\n")
   210  
   211  	// Create sorted slice of keys to ensure deterministic output
   212  	var keys = make([]string, 0, len(rawToOID))
   213  	for k := range rawToOID {
   214  		keys = append(keys, k)
   215  	}
   216  	sort.Strings(keys)
   217  	for _, k := range keys {
   218  		oid := rawToOID[k]
   219  		constantName := oid.GoConstant(CONST_PREFIX)
   220  		goName := oid.GoName("ExtKeyUsage")
   221  		buffer.WriteString(mapName)
   222  		buffer.WriteString("[")
   223  		buffer.WriteString(constantName)
   224  		buffer.WriteString("] = ")
   225  		buffer.WriteString(goName)
   226  		buffer.WriteString("\n")
   227  	}
   228  	return buffer.Bytes()
   229  }
   230  
   231  func generateEKUJSONStruct(rawToOID map[string]OID) []byte {
   232  	buffer := bytes.Buffer{}
   233  	buffer.WriteString("type auxExtendedKeyUsage struct {\n")
   234  
   235  	// Create sorted slice of keys to ensure deterministic output
   236  	var keys = make([]string, 0, len(rawToOID))
   237  	for k := range rawToOID {
   238  		keys = append(keys, k)
   239  	}
   240  	sort.Strings(keys)
   241  	for _, k := range keys {
   242  		oid := rawToOID[k]
   243  		buffer.WriteString(oid.StructFieldName())
   244  		buffer.WriteString(" bool `json:\"")
   245  		buffer.WriteString(oid.JSONName(""))
   246  		buffer.WriteString(",omitempty\" oid:\"")
   247  		buffer.WriteString(oid.OID)
   248  		buffer.WriteString("\"`\n")
   249  	}
   250  	buffer.WriteString("Unknown []string `json:\"unknown,omitempty\"`")
   251  	buffer.WriteString("}\n\n")
   252  	buffer.WriteString("func (aux *auxExtendedKeyUsage) populateFromASN1(oid asn1.ObjectIdentifier) {\n")
   253  	buffer.WriteString("s := oid.String()\n")
   254  	buffer.WriteString("switch s {\n")
   255  	for _, k := range keys {
   256  		oid := rawToOID[k]
   257  		buffer.WriteString("case ")
   258  		constantName := oid.GoConstant(CONST_PREFIX)
   259  		buffer.WriteString(constantName)
   260  		buffer.WriteString(":\n")
   261  		buffer.WriteString("aux.")
   262  		buffer.WriteString(oid.StructFieldName())
   263  		buffer.WriteString(" = true\n")
   264  	}
   265  	buffer.WriteString("default:\n")
   266  	buffer.WriteString("}\n")
   267  	buffer.WriteString("return")
   268  	buffer.WriteString("}\n\n")
   269  
   270  	buffer.WriteString("func (aux *auxExtendedKeyUsage) populateFromExtKeyUsage(eku ExtKeyUsage) {\n")
   271  	buffer.WriteString("switch eku {\n")
   272  	for _, k := range keys {
   273  		oid := rawToOID[k]
   274  		buffer.WriteString("case ")
   275  		ekuName := oid.GoName("ExtKeyUsage")
   276  		buffer.WriteString(ekuName)
   277  		buffer.WriteString(":\n")
   278  		buffer.WriteString("aux.")
   279  		buffer.WriteString(oid.StructFieldName())
   280  		buffer.WriteString(" = true\n")
   281  	}
   282  	buffer.WriteString("default:\n")
   283  	buffer.WriteString("}\n")
   284  	buffer.WriteString("return")
   285  	buffer.WriteString("}\n\n")
   286  
   287  	return buffer.Bytes()
   288  }
   289  
   290  func main() {
   291  	out, err := os.Create("extended_key_usage.go")
   292  	if err != nil {
   293  		panic(err.Error())
   294  	}
   295  	defer out.Close()
   296  	writeHeader(out)
   297  
   298  	resp, err := http.Get("https://raw.githubusercontent.com/zmap/constants/master/x509/extended_key_usage.csv")
   299  	if err != nil {
   300  		panic(err.Error())
   301  	}
   302  	defer resp.Body.Close()
   303  
   304  	rawToOID := make(map[string]OID)
   305  	r := csv.NewReader(resp.Body)
   306  	for lines := 0; ; lines++ {
   307  		record, err := r.Read()
   308  		if err == io.EOF {
   309  			break
   310  		}
   311  		if err != nil {
   312  			panic(err.Error())
   313  		}
   314  		if lines == 0 {
   315  			// Header row
   316  			continue
   317  		}
   318  		oid := record[COLUMN_IDX_OID]
   319  		shortName := record[COLUMN_IDX_SHORT_NAME]
   320  		rawToOID[oid] = OID{
   321  			OID:       oid,
   322  			ShortName: shortName,
   323  		}
   324  	}
   325  
   326  	out.Write([]byte("const (\n"))
   327  	constants := generateNameConstants(rawToOID)
   328  	out.Write(constants)
   329  	out.Write([]byte(")\n"))
   330  
   331  	out.Write([]byte("var (\n"))
   332  	oidDecls := generateASN1(rawToOID)
   333  	out.Write(oidDecls)
   334  	out.Write([]byte(")\n"))
   335  
   336  	integersConstants := generateIntegerConstants(rawToOID)
   337  	out.Write(integersConstants)
   338  
   339  	out.Write(generateEKUJSONStruct(rawToOID))
   340  
   341  	out.Write([]byte("\nvar ekuOIDs map[string]asn1.ObjectIdentifier\n\n"))
   342  	out.Write([]byte("\nvar ekuConstants map[string]ExtKeyUsage\n\n"))
   343  
   344  	out.Write([]byte("func init() {\n"))
   345  	mapEntries := generateOIDMap(rawToOID, "ekuOIDs")
   346  	out.Write(mapEntries)
   347  	out.Write([]byte("\n"))
   348  	intMapEntries := generateIntegerMap(rawToOID, "ekuConstants")
   349  	out.Write(intMapEntries)
   350  	out.Write([]byte("}\n"))
   351  }