/
builder.go
109 lines (87 loc) · 2.37 KB
/
builder.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
package ca_chain
import (
"bytes"
"crypto/tls"
"crypto/x509"
"encoding/hex"
"encoding/pem"
"fmt"
"io"
"strings"
"github.com/sirupsen/logrus"
)
const (
pemTypeCertificate = "CERTIFICATE"
)
type pemEncoder func(out io.Writer, b *pem.Block) error
type Builder interface {
fmt.Stringer
BuildChainFromTLSConnectionState(TLS *tls.ConnectionState) error
}
func NewBuilder(logger logrus.FieldLogger) Builder {
logger = logger.
WithField("context", "certificate-chain-build")
return &defaultBuilder{
certificates: make([]*x509.Certificate, 0),
seenCertificates: make(map[string]bool, 0),
resolver: newChainResolver(
newURLResolver(logger),
newVerifyResolver(logger),
),
encodePEM: pem.Encode,
logger: logger,
}
}
type defaultBuilder struct {
certificates []*x509.Certificate
seenCertificates map[string]bool
resolver resolver
encodePEM pemEncoder
logger logrus.FieldLogger
}
func (b *defaultBuilder) BuildChainFromTLSConnectionState(TLS *tls.ConnectionState) error {
for _, verifiedChain := range TLS.VerifiedChains {
b.logger.
WithField("chain-leaf", fmt.Sprintf("%v", verifiedChain)).
Debug("Processing chain")
err := b.fetchCertificatesFromVerifiedChain(verifiedChain)
if err != nil {
return fmt.Errorf("error while fetching certificates into the CA Chain: %v", err)
}
}
return nil
}
func (b *defaultBuilder) fetchCertificatesFromVerifiedChain(verifiedChain []*x509.Certificate) error {
var err error
if len(verifiedChain) < 1 {
return nil
}
verifiedChain, err = b.resolver.Resolve(verifiedChain)
if err != nil {
return fmt.Errorf("couldn't resolve certificates chain from the leaf certificate: %v", err)
}
for _, certificate := range verifiedChain {
b.addCertificate(certificate)
}
return nil
}
func (b *defaultBuilder) addCertificate(certificate *x509.Certificate) {
signature := hex.EncodeToString(certificate.Signature)
if b.seenCertificates[signature] {
return
}
b.seenCertificates[signature] = true
b.certificates = append(b.certificates, certificate)
}
func (b *defaultBuilder) String() string {
out := bytes.NewBuffer(nil)
for _, certificate := range b.certificates {
err := b.encodePEM(out, &pem.Block{Type: pemTypeCertificate, Bytes: certificate.Raw})
if err != nil {
b.logger.
WithError(err).
Warning("Failed to encode certificate from chain")
}
}
return strings.TrimSpace(out.String())
}