1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
|
//go:build ignore
package main
import (
"bufio"
"bytes"
_ "embed"
"fmt"
"log"
"os"
"regexp"
"strings"
"text/template"
)
const (
// Constants and flags used to generate the column number IDs.
// These were manually copied from lib/util/pkcs11t.h and pkcs11n.h.
NSSCK_VENDOR_NSS = 0x4E534350
CKA_VENDOR_DEFINED = 0x80000000
CKA_NSS = CKA_VENDOR_DEFINED | NSSCK_VENDOR_NSS
CKA_TRUST = CKA_NSS + 0x2000
CKA_SUBPRIME_BITS = 0x00000134
CKF_ARRAY_ATTRIBUTE = 0x40000000
)
// This file contains the knownAttributes array, which is the list of columns.
//
//go:embed nss/lib/softoken/sdb.c
var sdb []byte
// This file defines most of the attributes that have columns in the db.
//
//go:embed nss/lib/util/pkcs11t.h
var pkcs11t []byte
// This file defines a few more attributes with columns in the db.
//
//go:embed nss/lib/util/pkcs11n.h
var pkcs11n []byte
func main() {
attributes := parseKnownAttributes()
columns := make(map[string]string, len(attributes))
for _, attr := range attributes {
columns[attr] = ""
}
err := findDefinitions(pkcs11t, columns)
if err != nil {
panic(err)
}
err = findDefinitions(pkcs11n, columns)
if err != nil {
panic(err)
}
for k, v := range columns {
if v != "" {
continue
}
fmt.Printf("%s column is unset\n", k)
os.Exit(1)
}
const templ = `// generated by nssdb/generate/main.go
package nssdb
var columns = map[string]string{
{{- range $k, $v := . }}
{{ printf "%q" $k}}: {{ printf "%q" $v }},
{{- end }}
}
`
t, err := template.New("go").Parse(templ)
if err != nil {
panic(err)
}
t.Execute(os.Stdout, columns)
log.Printf("Successfully generated column names for %d attributes\n", len(columns))
}
// Get the column attribute names from the array in lib/softoken/sdb.c that
// looks like this:
//
// static const CK_ATTRIBUTE_TYPE known_attributes[] = {
// CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION,
// CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER,
// ...
// }
func parseKnownAttributes() []string {
scanner := bufio.NewScanner(bytes.NewReader(sdb))
var columns []string
inKnownAttributes := false
for scanner.Scan() {
switch {
case scanner.Text() == "static const CK_ATTRIBUTE_TYPE known_attributes[] = {":
inKnownAttributes = true
continue
case !inKnownAttributes:
continue
case scanner.Text() == "};":
return columns
default:
for _, col := range strings.Split(scanner.Text(), ",") {
col = strings.TrimSpace(col)
if col == "" {
continue
}
columns = append(columns, col)
}
}
}
return columns
}
var (
defineCKA = regexp.MustCompile("^#define (CKA_[0-9A-Z_]+) (.*)")
ckaNSS = regexp.MustCompile(`\(CKA_NSS \+ (\d+)\)`)
ckaTrust = regexp.MustCompile(`\(CKA_TRUST \+ (\d+)\)`)
ckfArray = regexp.MustCompile(`\(CKF_ARRAY_ATTRIBUTE \| 0x([0-9A-Z]+)U?L\)`)
)
// Find the integer used in the sqlite column name for an attribute.
// Examples of the 5 types of lines we have to parse:
//
// #define CKA_PRIVATE 0x00000002UL
// #define CKA_TRUST_DATA_ENCIPHERMENT (CKA_TRUST + 4)
// #define CKA_NSS_EMAIL (CKA_NSS + 2)
// #define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x00000211UL)
// #define CKA_SUB_PRIME_BITS CKA_SUBPRIME_BITS
func findDefinitions(file []byte, columns map[string]string) error {
scanner := bufio.NewScanner(bytes.NewReader(file))
for scanner.Scan() {
matches := defineCKA.FindStringSubmatch(scanner.Text())
if len(matches) != 3 {
continue
}
attr := matches[1]
if _, ok := columns[attr]; !ok {
continue
}
val := matches[2]
switch {
case strings.HasPrefix(val, "0x"):
// 0x01UL
// 0x01L
val = strings.TrimSuffix(val, "L")
val = strings.TrimSuffix(val, "U")
var x int
_, err := fmt.Sscanf(val, "0x%X", &x)
if err != nil {
return fmt.Errorf("failed to parse %q: %w", scanner.Text(), err)
}
columns[attr] = fmt.Sprintf("a%x", x)
case ckaNSS.MatchString(scanner.Text()):
matches := ckaNSS.FindStringSubmatch(scanner.Text())
var plus int
_, err := fmt.Sscanf(matches[1], "%d", &plus)
if err != nil {
return fmt.Errorf("failed to parse %q: %w", scanner.Text(), err)
}
columns[attr] = fmt.Sprintf("a%x", CKA_NSS+plus)
case ckaTrust.MatchString(scanner.Text()):
matches := ckaTrust.FindStringSubmatch(scanner.Text())
var plus int
_, err := fmt.Sscanf(matches[1], "%d", &plus)
if err != nil {
return fmt.Errorf("failed to parse %q: %w", scanner.Text(), err)
}
columns[attr] = fmt.Sprintf("a%x", CKA_TRUST+plus)
case ckfArray.MatchString(scanner.Text()):
matches := ckfArray.FindStringSubmatch(scanner.Text())
var x int
_, err := fmt.Sscanf(matches[1], "%X", &x)
if err != nil {
return fmt.Errorf("failed to parse %q: %w", scanner.Text(), err)
}
columns[attr] = fmt.Sprintf("a%x", CKF_ARRAY_ATTRIBUTE|x)
case val == "CKA_SUBPRIME_BITS":
columns[attr] = fmt.Sprintf("a%x", CKA_SUBPRIME_BITS)
default:
return fmt.Errorf("Cannot parse %q", scanner.Text())
}
}
return nil
}
|