-
Notifications
You must be signed in to change notification settings - Fork 0
/
resolver_url.go
107 lines (82 loc) · 2.39 KB
/
resolver_url.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
// Inspired by https://github.com/zakjan/cert-chain-resolver/blob/master/certUtil/chain.go
// which is licensed on a MIT license.
//
// Shout out to Jan Žák (http://zakjan.cz) original author of `certUtil` package and other
// contributors who updated it!
package ca_chain
import (
"crypto/x509"
"fmt"
"github.com/sirupsen/logrus"
)
const defaultURLResolverLoopLimit = 15
type fetcher func(url string) ([]byte, error)
type decoder func(data []byte) (*x509.Certificate, error)
type urlResolver struct {
logger logrus.FieldLogger
fetcher fetcher
decoder decoder
loopLimit int
}
func newURLResolver(logger logrus.FieldLogger) resolver {
return &urlResolver{
logger: logger,
fetcher: fetchRemoteCertificate,
decoder: decodeCertificate,
loopLimit: defaultURLResolverLoopLimit,
}
}
func (r *urlResolver) Resolve(certs []*x509.Certificate) ([]*x509.Certificate, error) {
if len(certs) < 1 {
return nil, nil
}
loop := 0
for {
loop++
if loop >= r.loopLimit {
r.
logger.
Warning("urlResolver loop limit exceeded; exiting the loop")
break
}
certificate := certs[len(certs)-1]
log := prepareCertificateLogger(r.logger, certificate)
if certificate.IssuingCertificateURL == nil {
log.Debug("Certificate doesn't provide parent URL: exiting the loop")
break
}
newCert, err := r.fetchIssuerCertificate(certificate)
if err != nil {
return nil, fmt.Errorf("error while fetching issuer certificate: %v", err)
}
certs = append(certs, newCert)
if isSelfSigned(newCert) {
log.Debug("Fetched issuer certificate is a ROOT certificate so exiting the loop")
break
}
}
return certs, nil
}
func (r *urlResolver) fetchIssuerCertificate(cert *x509.Certificate) (*x509.Certificate, error) {
log := prepareCertificateLogger(r.logger, cert).
WithField("method", "fetchIssuerCertificate")
issuerURL := cert.IssuingCertificateURL[0]
data, err := r.fetcher(issuerURL)
if err != nil {
log.
WithError(err).
WithField("issuerURL", issuerURL).
Warning("Remote certificate fetching error")
return nil, fmt.Errorf("remote fetch failure: %v", err)
}
newCert, err := r.decoder(data)
if err != nil {
log.
WithError(err).
Warning("Certificate decoding error")
return nil, fmt.Errorf("decoding failure: %v", err)
}
preparePrefixedCertificateLogger(log, newCert, "newCert").
Debug("Appending the certificate to the chain")
return newCert, nil
}