-
Notifications
You must be signed in to change notification settings - Fork 5
/
revocation.go
172 lines (159 loc) · 5.12 KB
/
revocation.go
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
package revocation
import (
"crypto/x509"
"errors"
"fmt"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
"github.com/caddyserver/caddy/v2/modules/caddytls"
"github.com/gr33nbl00d/caddy-revocation-validator/config"
"github.com/gr33nbl00d/caddy-revocation-validator/crl"
"github.com/gr33nbl00d/caddy-revocation-validator/ocsp"
"go.uber.org/zap"
"os"
)
func init() {
caddy.RegisterModule(&CertRevocationValidator{})
}
// CertRevocationValidator Allows checking of client certificate revocation status based on CRL or OCSP
type CertRevocationValidator struct {
// Mode defines the "Revocation Check Mode"
// Supported Values 'prefer_ocsp', 'prefer_crl', 'ocsp_only', 'crl_only', 'disabled'
// See https://github.com/Gr33nbl00d/caddy-revocation-validator#mode
Mode string `json:"mode"`
// CRLConfig Contains the certificate revocation list configuration (Optional)
CRLConfig *config.CRLConfig `json:"crl_config,omitempty"`
// OCSPConfig Contains the Online Certificate Status Protocol configuration (Optional)
OCSPConfig *config.OCSPConfig `json:"ocsp_config,omitempty"`
logger *zap.Logger
ctx caddy.Context
crlRevocationChecker *crl.CRLRevocationChecker
ocspRevocationChecker *ocsp.OCSPRevocationChecker
ModeParsed config.RevocationCheckMode `json:"-"`
}
func (c *CertRevocationValidator) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "tls.client_auth.verifier.revocation",
New: func() caddy.Module {
return new(CertRevocationValidator)
},
}
}
// Provision sets up c
func (c *CertRevocationValidator) Provision(ctx caddy.Context) error {
c.ctx = ctx
c.logger = ctx.Logger(c)
c.logger.Info("start provisioning of caddy revocation validator")
if isCRLCheckingEnabled(c) {
c.crlRevocationChecker = &crl.CRLRevocationChecker{}
}
c.ocspRevocationChecker = &ocsp.OCSPRevocationChecker{}
err := ParseConfig(c)
if err != nil {
return err
}
c.logger.Info("validating Config")
err = validateConfig(c)
if err != nil {
return err
}
if isCRLCheckingEnabled(c) {
c.logger.Info("crl checking was enabled start CRL provisioning")
err = c.crlRevocationChecker.Provision(c.CRLConfig, c.logger)
if err != nil {
return err
}
}
c.logger.Info("start ocsp provisioning")
err = c.ocspRevocationChecker.Provision(c.OCSPConfig, c.logger)
if err != nil {
return err
}
c.logger.Info("finished provisioning of caddy revocation validator")
return nil
}
func validateConfig(c *CertRevocationValidator) error {
if c.ModeParsed == config.RevocationCheckModeDisabled {
return nil
}
if isCRLCheckingEnabled(c) {
if c.CRLConfig == nil {
return errors.New("for CRL checking a working directory need to be defined in crl_config")
} else {
if c.CRLConfig.WorkDir == "" {
return errors.New("for CRL checking a working directory need to be defined in crl_config")
}
stat, err := os.Stat(c.CRLConfig.WorkDir)
if err != nil {
return fmt.Errorf("error accessing working directory information %v", err)
}
if stat.IsDir() == false {
return fmt.Errorf("working directory is not a directory %v", c.CRLConfig.WorkDir)
}
}
}
return nil
}
func (c *CertRevocationValidator) Cleanup() error {
if isCRLCheckingEnabled(c) {
err := c.crlRevocationChecker.Cleanup()
if err != nil {
return err
}
}
err := c.ocspRevocationChecker.Cleanup()
if err != nil {
return err
}
return nil
}
func (c *CertRevocationValidator) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
caddyConfig, err := parseConfigFromCaddyfile(d)
if err != nil {
return err
}
c.OCSPConfig = caddyConfig.OCSPConfig
c.CRLConfig = caddyConfig.CRLConfig
c.Mode = caddyConfig.Mode
err = validateConfig(c)
if err != nil {
return err
}
return nil
}
func (c *CertRevocationValidator) VerifyClientCertificate(_ [][]byte, verifiedChains [][]*x509.Certificate) error {
if len(verifiedChains) > 0 {
clientCertificate := verifiedChains[0][0]
if isOCSPCheckingEnabled(c) {
revoked, err := c.ocspRevocationChecker.IsRevoked(clientCertificate, verifiedChains)
if err != nil {
return err
}
if revoked.Revoked {
return errors.New("client certificate was revoked")
}
}
if isCRLCheckingEnabled(c) {
revoked, err := c.crlRevocationChecker.IsRevoked(clientCertificate, verifiedChains)
if err != nil {
return err
}
if revoked.Revoked {
return errors.New("client certificate was revoked")
}
}
}
return nil
}
func isOCSPCheckingEnabled(c *CertRevocationValidator) bool {
return c.ModeParsed == config.RevocationCheckModePreferCRL || c.ModeParsed == config.RevocationCheckModePreferOCSP || c.ModeParsed == config.RevocationCheckModeOCSPOnly
}
func isCRLCheckingEnabled(c *CertRevocationValidator) bool {
return c.ModeParsed == config.RevocationCheckModePreferCRL || c.ModeParsed == config.RevocationCheckModePreferOCSP || c.ModeParsed == config.RevocationCheckModeCRLOnly
}
// Interface guards
var (
_ caddy.Provisioner = (*CertRevocationValidator)(nil)
_ caddy.CleanerUpper = (*CertRevocationValidator)(nil)
_ caddytls.ClientCertificateVerifier = (*CertRevocationValidator)(nil)
)