File: builder.go

package info (click to toggle)
gitlab-ci-multi-runner 14.10.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 31,248 kB
  • sloc: sh: 1,694; makefile: 384; asm: 79; ruby: 68
file content (109 lines) | stat: -rw-r--r-- 2,428 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
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),
		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: %w", 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: %w", 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())
}