github.com/secure-build/gitlab-runner@v12.5.0+incompatible/helpers/tls/ca_chain/helpers.go (about) 1 // Inspired by https://github.com/zakjan/cert-chain-resolver/blob/master/certUtil/io.go 2 // which is licensed on a MIT license. 3 // 4 // Shout out to Jan Žák (http://zakjan.cz) original author of `certUtil` package and other 5 // contributors who updated it! 6 7 package ca_chain 8 9 import ( 10 "bytes" 11 "crypto/x509" 12 "encoding/pem" 13 "fmt" 14 "io/ioutil" 15 "net/http" 16 "strings" 17 18 "github.com/fullsailor/pkcs7" 19 "github.com/sirupsen/logrus" 20 ) 21 22 const ( 23 pemStart = "-----BEGIN " 24 pemCertBlockType = "CERTIFICATE" 25 ) 26 27 type ErrorInvalidCertificate struct { 28 inner error 29 nonCertBlockType bool 30 nilBlock bool 31 } 32 33 func (e *ErrorInvalidCertificate) Error() string { 34 msg := []string{"invalid certificate"} 35 36 if e.nilBlock { 37 msg = append(msg, "empty PEM block") 38 } else if e.nonCertBlockType { 39 msg = append(msg, "non-certificate PEM block") 40 } else if e.inner != nil { 41 msg = append(msg, e.inner.Error()) 42 } 43 44 return strings.Join(msg, ": ") 45 } 46 47 func decodeCertificate(data []byte) (*x509.Certificate, error) { 48 if isPEM(data) { 49 block, _ := pem.Decode(data) 50 if block == nil { 51 return nil, &ErrorInvalidCertificate{nilBlock: true} 52 } 53 if block.Type != pemCertBlockType { 54 return nil, &ErrorInvalidCertificate{nonCertBlockType: true} 55 } 56 57 data = block.Bytes 58 } 59 60 cert, err := x509.ParseCertificate(data) 61 if err == nil { 62 return cert, nil 63 } 64 65 p, err := pkcs7.Parse(data) 66 if err == nil { 67 return p.Certificates[0], nil 68 } 69 70 return nil, &ErrorInvalidCertificate{inner: err} 71 } 72 73 func isPEM(data []byte) bool { 74 return bytes.HasPrefix(data, []byte(pemStart)) 75 } 76 77 func isSelfSigned(cert *x509.Certificate) bool { 78 return cert.CheckSignatureFrom(cert) == nil 79 } 80 81 func prepareCertificateLogger(logger logrus.FieldLogger, cert *x509.Certificate) logrus.FieldLogger { 82 return preparePrefixedCertificateLogger(logger, cert, "") 83 } 84 85 func preparePrefixedCertificateLogger(logger logrus.FieldLogger, cert *x509.Certificate, prefix string) logrus.FieldLogger { 86 return logger. 87 WithFields(logrus.Fields{ 88 fmt.Sprintf("%sSubject", prefix): cert.Subject.CommonName, 89 fmt.Sprintf("%sIssuer", prefix): cert.Issuer.CommonName, 90 fmt.Sprintf("%sSerial", prefix): cert.SerialNumber.String(), 91 fmt.Sprintf("%sIssuerCertURL", prefix): cert.IssuingCertificateURL, 92 }) 93 } 94 95 func fetchRemoteCertificate(url string) ([]byte, error) { 96 resp, err := http.Get(url) 97 if resp != nil { 98 defer resp.Body.Close() 99 } 100 if err != nil { 101 return nil, err 102 } 103 104 data, err := ioutil.ReadAll(resp.Body) 105 if err != nil { 106 return nil, err 107 } 108 109 return data, nil 110 } 111 112 func verifyCertificate(cert *x509.Certificate) ([][]*x509.Certificate, error) { 113 return cert.Verify(x509.VerifyOptions{}) 114 }