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 }