File: main.go

package info (click to toggle)
golang-github-smallstep-crypto 0.63.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,800 kB
  • sloc: sh: 66; makefile: 50
file content (197 lines) | stat: -rw-r--r-- 5,055 bytes parent folder | download
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
}