github.com/secure-build/gitlab-runner@v12.5.0+incompatible/helpers/tls/ca_chain/builder.go (about) 1 package ca_chain 2 3 import ( 4 "bytes" 5 "crypto/tls" 6 "crypto/x509" 7 "encoding/hex" 8 "encoding/pem" 9 "fmt" 10 "io" 11 "strings" 12 13 "github.com/sirupsen/logrus" 14 ) 15 16 const ( 17 pemTypeCertificate = "CERTIFICATE" 18 ) 19 20 type pemEncoder func(out io.Writer, b *pem.Block) error 21 22 type Builder interface { 23 fmt.Stringer 24 25 BuildChainFromTLSConnectionState(TLS *tls.ConnectionState) error 26 } 27 28 func NewBuilder(logger logrus.FieldLogger) Builder { 29 logger = logger. 30 WithField("context", "certificate-chain-build") 31 32 return &defaultBuilder{ 33 certificates: make([]*x509.Certificate, 0), 34 seenCertificates: make(map[string]bool, 0), 35 resolver: newChainResolver( 36 newURLResolver(logger), 37 newVerifyResolver(logger), 38 ), 39 encodePEM: pem.Encode, 40 logger: logger, 41 } 42 } 43 44 type defaultBuilder struct { 45 certificates []*x509.Certificate 46 seenCertificates map[string]bool 47 48 resolver resolver 49 encodePEM pemEncoder 50 51 logger logrus.FieldLogger 52 } 53 54 func (b *defaultBuilder) BuildChainFromTLSConnectionState(TLS *tls.ConnectionState) error { 55 for _, verifiedChain := range TLS.VerifiedChains { 56 b.logger. 57 WithField("chain-leaf", fmt.Sprintf("%v", verifiedChain)). 58 Debug("Processing chain") 59 err := b.fetchCertificatesFromVerifiedChain(verifiedChain) 60 if err != nil { 61 return fmt.Errorf("error while fetching certificates into the CA Chain: %v", err) 62 } 63 } 64 65 return nil 66 } 67 68 func (b *defaultBuilder) fetchCertificatesFromVerifiedChain(verifiedChain []*x509.Certificate) error { 69 var err error 70 71 if len(verifiedChain) < 1 { 72 return nil 73 } 74 75 verifiedChain, err = b.resolver.Resolve(verifiedChain) 76 if err != nil { 77 return fmt.Errorf("couldn't resolve certificates chain from the leaf certificate: %v", err) 78 } 79 80 for _, certificate := range verifiedChain { 81 b.addCertificate(certificate) 82 } 83 84 return nil 85 } 86 87 func (b *defaultBuilder) addCertificate(certificate *x509.Certificate) { 88 signature := hex.EncodeToString(certificate.Signature) 89 if b.seenCertificates[signature] { 90 return 91 } 92 93 b.seenCertificates[signature] = true 94 b.certificates = append(b.certificates, certificate) 95 } 96 97 func (b *defaultBuilder) String() string { 98 out := bytes.NewBuffer(nil) 99 for _, certificate := range b.certificates { 100 err := b.encodePEM(out, &pem.Block{Type: pemTypeCertificate, Bytes: certificate.Raw}) 101 if err != nil { 102 b.logger. 103 WithError(err). 104 Warning("Failed to encode certificate from chain") 105 } 106 } 107 108 return strings.TrimSpace(out.String()) 109 }