@@ -540,7 +540,7 @@ func NewRoundTripperFromConfig(cfg HTTPClientConfig, name string, optFuncs ...HT
540540 return newRT (tlsConfig )
541541 }
542542
543- return NewTLSRoundTripper (tlsConfig , cfg .TLSConfig .CAFile , newRT )
543+ return NewTLSRoundTripper (tlsConfig , cfg .TLSConfig .CAFile , cfg . TLSConfig . CertFile , cfg . TLSConfig . KeyFile , newRT )
544544}
545545
546546type authorizationCredentialsRoundTripper struct {
@@ -709,7 +709,7 @@ func (rt *oauth2RoundTripper) RoundTrip(req *http.Request) (*http.Response, erro
709709 if len (rt .config .TLSConfig .CAFile ) == 0 {
710710 t , _ = tlsTransport (tlsConfig )
711711 } else {
712- t , err = NewTLSRoundTripper (tlsConfig , rt .config .TLSConfig .CAFile , tlsTransport )
712+ t , err = NewTLSRoundTripper (tlsConfig , rt .config .TLSConfig .CAFile , rt . config . TLSConfig . CertFile , rt . config . TLSConfig . KeyFile , tlsTransport )
713713 if err != nil {
714714 return nil , err
715715 }
@@ -838,12 +838,39 @@ func (c *TLSConfig) SetDirectory(dir string) {
838838 c .KeyFile = JoinDir (dir , c .KeyFile )
839839}
840840
841+ // UnmarshalYAML implements the yaml.Unmarshaler interface.
842+ func (c * TLSConfig ) UnmarshalYAML (unmarshal func (interface {}) error ) error {
843+ type plain TLSConfig
844+ return unmarshal ((* plain )(c ))
845+ }
846+
847+ // readCertAndKey reads the cert and key files from the disk.
848+ func readCertAndKey (certFile , keyFile string ) ([]byte , []byte , error ) {
849+ certData , err := ioutil .ReadFile (certFile )
850+ if err != nil {
851+ return nil , nil , err
852+ }
853+
854+ keyData , err := ioutil .ReadFile (keyFile )
855+ if err != nil {
856+ return nil , nil , err
857+ }
858+
859+ return certData , keyData , nil
860+ }
861+
841862// getClientCertificate reads the pair of client cert and key from disk and returns a tls.Certificate.
842- func (c * TLSConfig ) getClientCertificate (* tls.CertificateRequestInfo ) (* tls.Certificate , error ) {
843- cert , err := tls .LoadX509KeyPair (c .CertFile , c .KeyFile )
863+ func (c * TLSConfig ) getClientCertificate (_ * tls.CertificateRequestInfo ) (* tls.Certificate , error ) {
864+ certData , keyData , err := readCertAndKey (c .CertFile , c .KeyFile )
865+ if err != nil {
866+ return nil , fmt .Errorf ("unable to read specified client cert (%s) & key (%s): %s" , c .CertFile , c .KeyFile , err )
867+ }
868+
869+ cert , err := tls .X509KeyPair (certData , keyData )
844870 if err != nil {
845871 return nil , fmt .Errorf ("unable to use specified client cert (%s) & key (%s): %s" , c .CertFile , c .KeyFile , err )
846872 }
873+
847874 return & cert , nil
848875}
849876
@@ -869,23 +896,30 @@ func updateRootCA(cfg *tls.Config, b []byte) bool {
869896// tlsRoundTripper is a RoundTripper that updates automatically its TLS
870897// configuration whenever the content of the CA file changes.
871898type tlsRoundTripper struct {
872- caFile string
899+ caFile string
900+ certFile string
901+ keyFile string
902+
873903 // newRT returns a new RoundTripper.
874904 newRT func (* tls.Config ) (http.RoundTripper , error )
875905
876- mtx sync.RWMutex
877- rt http.RoundTripper
878- hashCAFile []byte
879- tlsConfig * tls.Config
906+ mtx sync.RWMutex
907+ rt http.RoundTripper
908+ hashCAFile []byte
909+ hashCertFile []byte
910+ hashKeyFile []byte
911+ tlsConfig * tls.Config
880912}
881913
882914func NewTLSRoundTripper (
883915 cfg * tls.Config ,
884- caFile string ,
916+ caFile , certFile , keyFile string ,
885917 newRT func (* tls.Config ) (http.RoundTripper , error ),
886918) (http.RoundTripper , error ) {
887919 t := & tlsRoundTripper {
888920 caFile : caFile ,
921+ certFile : certFile ,
922+ keyFile : keyFile ,
889923 newRT : newRT ,
890924 tlsConfig : cfg ,
891925 }
@@ -895,33 +929,44 @@ func NewTLSRoundTripper(
895929 return nil , err
896930 }
897931 t .rt = rt
898- _ , t .hashCAFile , err = t .getCAWithHash ()
932+ _ , t .hashCAFile , t . hashCertFile , t . hashKeyFile , err = t .getTLSFilesWithHash ()
899933 if err != nil {
900934 return nil , err
901935 }
902936
903937 return t , nil
904938}
905939
906- func (t * tlsRoundTripper ) getCAWithHash () ([]byte , []byte , error ) {
907- b , err := readCAFile (t .caFile )
940+ func (t * tlsRoundTripper ) getTLSFilesWithHash () ([] byte , [] byte , []byte , []byte , error ) {
941+ b1 , err := readCAFile (t .caFile )
908942 if err != nil {
909- return nil , nil , err
943+ return nil , nil , nil , nil , err
944+ }
945+ h1 := sha256 .Sum256 (b1 )
946+
947+ var h2 , h3 [32 ]byte
948+ if t .certFile != "" {
949+ b2 , b3 , err := readCertAndKey (t .certFile , t .keyFile )
950+ if err != nil {
951+ return nil , nil , nil , nil , err
952+ }
953+ h2 , h3 = sha256 .Sum256 (b2 ), sha256 .Sum256 (b3 )
910954 }
911- h := sha256 .Sum256 (b )
912- return b , h [:], nil
913955
956+ return b1 , h1 [:], h2 [:], h3 [:], nil
914957}
915958
916959// RoundTrip implements the http.RoundTrip interface.
917960func (t * tlsRoundTripper ) RoundTrip (req * http.Request ) (* http.Response , error ) {
918- b , h , err := t .getCAWithHash ()
961+ caData , caHash , certHash , keyHash , err := t .getTLSFilesWithHash ()
919962 if err != nil {
920963 return nil , err
921964 }
922965
923966 t .mtx .RLock ()
924- equal := bytes .Equal (h [:], t .hashCAFile )
967+ equal := bytes .Equal (caHash [:], t .hashCAFile ) &&
968+ bytes .Equal (certHash [:], t .hashCertFile ) &&
969+ bytes .Equal (keyHash [:], t .hashKeyFile )
925970 rt := t .rt
926971 t .mtx .RUnlock ()
927972 if equal {
@@ -930,8 +975,10 @@ func (t *tlsRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
930975 }
931976
932977 // Create a new RoundTripper.
978+ // The cert and key files are read separately by the client
979+ // using GetClientCertificate.
933980 tlsConfig := t .tlsConfig .Clone ()
934- if ! updateRootCA (tlsConfig , b ) {
981+ if ! updateRootCA (tlsConfig , caData ) {
935982 return nil , fmt .Errorf ("unable to use specified CA cert %s" , t .caFile )
936983 }
937984 rt , err = t .newRT (tlsConfig )
@@ -942,7 +989,9 @@ func (t *tlsRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
942989
943990 t .mtx .Lock ()
944991 t .rt = rt
945- t .hashCAFile = h [:]
992+ t .hashCAFile = caHash [:]
993+ t .hashCertFile = certHash [:]
994+ t .hashKeyFile = keyHash [:]
946995 t .mtx .Unlock ()
947996
948997 return rt .RoundTrip (req )
0 commit comments