forked from adamlaska/boulder
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlint.go
More file actions
131 lines (121 loc) · 4.13 KB
/
lint.go
File metadata and controls
131 lines (121 loc) · 4.13 KB
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
package lint
import (
"crypto"
"crypto/ecdsa"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"fmt"
"strings"
zlintx509 "github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3"
"github.com/zmap/zlint/v3/lint"
)
// Check accomplishes the entire process of linting: it generates a throwaway
// signing key, uses that to create a throwaway cert, and runs a default set
// of lints (everything except for the ETSI and EV lints) against it. This is
// the primary public interface of this package, but it can be inefficient;
// creating a new signer and a new lint registry are expensive operations which
// performance-sensitive clients may want to cache.
func Check(tbs, issuer *x509.Certificate, subjectPubKey crypto.PublicKey, realSigner crypto.Signer, skipLints []string) error {
lintSigner, err := MakeSigner(realSigner)
if err != nil {
return err
}
lintCert, err := MakeLintCert(tbs, issuer, subjectPubKey, lintSigner)
if err != nil {
return err
}
reg, err := MakeRegistry(skipLints)
if err != nil {
return err
}
return LintCert(lintCert, reg)
}
// MakeSigner creates a throwaway crypto.Signer with the same key algorithm
// as the given Signer. This is useful if you intend to lint many certs are
// okay using the same throwaway key to sign all of them.
func MakeSigner(realSigner crypto.Signer) (crypto.Signer, error) {
var lintSigner crypto.Signer
var err error
switch k := realSigner.Public().(type) {
case *rsa.PublicKey:
lintSigner, err = rsa.GenerateKey(rand.Reader, k.Size()*8)
if err != nil {
return nil, fmt.Errorf("failed to create RSA lint signer: %w", err)
}
case *ecdsa.PublicKey:
lintSigner, err = ecdsa.GenerateKey(k.Curve, rand.Reader)
if err != nil {
return nil, fmt.Errorf("failed to create ECDSA lint signer: %w", err)
}
default:
return nil, fmt.Errorf("unsupported lint signer type: %T", k)
}
return lintSigner, nil
}
// MakeRegistry creates a zlint Registry of lints to run, filtering out the
// EV- and ETSI-specific lints, as well as any others specified.
func MakeRegistry(skipLints []string) (lint.Registry, error) {
reg, err := lint.GlobalRegistry().Filter(lint.FilterOptions{
ExcludeNames: skipLints,
ExcludeSources: []lint.LintSource{
lint.CABFEVGuidelines,
lint.EtsiEsi,
},
})
if err != nil {
return nil, fmt.Errorf("failed to create lint registry: %w", err)
}
return reg, nil
}
// MakeLintCert creates a throwaway x509.Certificate which can be linted.
// Only use the result from MakeSigner as the final argument.
func MakeLintCert(tbs, issuer *x509.Certificate, subjectPubKey crypto.PublicKey, lintSigner crypto.Signer) (*zlintx509.Certificate, error) {
lintCertBytes, err := x509.CreateCertificate(rand.Reader, tbs, issuer, subjectPubKey, lintSigner)
if err != nil {
return nil, fmt.Errorf("failed to create lint certificate: %w", err)
}
lintCert, err := zlintx509.ParseCertificate(lintCertBytes)
if err != nil {
return nil, fmt.Errorf("failed to parse lint certificate: %w", err)
}
return lintCert, nil
}
// LintCert runs the given set of lints across the given cert and returns
// an error containing the names of all failed lints, or nil.
func LintCert(lintCert *zlintx509.Certificate, lints lint.Registry) error {
lintRes := zlint.LintCertificateEx(lintCert, lints)
if lintRes.NoticesPresent || lintRes.WarningsPresent || lintRes.ErrorsPresent || lintRes.FatalsPresent {
var failedLints []string
for lintName, result := range lintRes.Results {
if result.Status > lint.Pass {
failedLints = append(failedLints, lintName)
}
}
return fmt.Errorf("failed lints: %s", strings.Join(failedLints, ", "))
}
return nil
}
type Linter struct {
signer crypto.Signer
registry lint.Registry
}
func NewLinter(realSigner crypto.Signer, skipLints []string) (*Linter, error) {
signer, err := MakeSigner(realSigner)
if err != nil {
return nil, err
}
reg, err := MakeRegistry(skipLints)
if err != nil {
return nil, err
}
return &Linter{signer, reg}, nil
}
func (l Linter) LintTBS(tbs, issuer *x509.Certificate, subjectPubKey crypto.PublicKey) error {
cert, err := MakeLintCert(tbs, issuer, subjectPubKey, l.signer)
if err != nil {
return err
}
return LintCert(cert, l.registry)
}