-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix golang windows cert store bug - need to check list of RootCAs plu…
…s allow Windows APIs to be called to dynamically load root CA if necessary (#20)
- Loading branch information
Showing
2 changed files
with
115 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// +build !windows | ||
|
||
package windowscertbug | ||
|
||
import ( | ||
"crypto/tls" | ||
"crypto/x509" | ||
) | ||
|
||
// VerifyCertificate for platforms without the cert bug does not | ||
// do anything special. | ||
func VerifyCertificate(cert *x509.Certificate, opts x509.VerifyOptions) (chains [][]*x509.Certificate, err error) { | ||
return cert.Verify(opts) | ||
} | ||
|
||
// PrepareClientTLSConfig for platforms without the cert bug does not | ||
// do anything special. | ||
func PrepareClientTLSConfig(config *tls.Config) *tls.Config { | ||
return config | ||
} | ||
|
||
// PrepareServerTLSConfig for platforms without the cert bug does not | ||
// do anything special. | ||
func PrepareServerTLSConfig(config *tls.Config) *tls.Config { | ||
return config | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package windowscertbug | ||
|
||
import ( | ||
"crypto/tls" | ||
"crypto/x509" | ||
"errors" | ||
) | ||
|
||
// Some background: https://github.com/golang/go/issues/34937 | ||
// The below routines work around golang's windows certificate shortcomings. | ||
// For all these routines NOTE that their usage assumes that all system roots | ||
// are included. | ||
|
||
// VerifyCertificate will call Verify twice if needed, to ensure | ||
// the Windows root store is completely checked. | ||
func VerifyCertificate(cert *x509.Certificate, opts x509.VerifyOptions) (chains [][]*x509.Certificate, err error) { | ||
if opts.Roots != nil { | ||
if chains, err := cert.Verify(opts); err == nil { | ||
return chains, err | ||
} | ||
// the given roots did not work, so now try Verify with nil Roots | ||
opts.Roots = nil | ||
} | ||
return cert.Verify(opts) | ||
} | ||
|
||
// PrepareClientTLSConfig will modify the given tls.Config so that | ||
// it does custom cert verification on Windows to workaround a golang bug. | ||
func PrepareClientTLSConfig(config *tls.Config) *tls.Config { | ||
if config.InsecureSkipVerify { | ||
return config | ||
} | ||
if config.RootCAs == nil { | ||
return config | ||
} | ||
config.InsecureSkipVerify = true | ||
config.VerifyPeerCertificate = makeVerifyPeer(config, false) | ||
return config | ||
} | ||
|
||
// PrepareServerTLSConfig will modify the given tls.Config so that | ||
// it does custom cert verification on Windows to workaround a golang bug. | ||
func PrepareServerTLSConfig(config *tls.Config) *tls.Config { | ||
if config.InsecureSkipVerify { | ||
return config | ||
} | ||
if config.ClientAuth < tls.VerifyClientCertIfGiven { | ||
return config | ||
} | ||
if config.ClientCAs == nil { | ||
return config | ||
} | ||
config.InsecureSkipVerify = true | ||
config.VerifyPeerCertificate = makeVerifyPeer(config, true) | ||
return config | ||
} | ||
|
||
// return a custom VerifyPeerCertificate func | ||
// this is based on https://tip.golang.org/pkg/crypto/tls/#example_Config_verifyPeerCertificate | ||
func makeVerifyPeer(tlsConfig *tls.Config, asServer bool) func([][]byte, [][]*x509.Certificate) error { | ||
return func(certificates [][]byte, _ [][]*x509.Certificate) error { | ||
certs := make([]*x509.Certificate, len(certificates)) | ||
for i, asn1Data := range certificates { | ||
cert, err := x509.ParseCertificate(asn1Data) | ||
if err != nil { | ||
return errors.New("tls: failed to parse certificate from server: " + err.Error()) | ||
} | ||
certs[i] = cert | ||
} | ||
|
||
opts := x509.VerifyOptions{ | ||
Roots: tlsConfig.RootCAs, | ||
DNSName: tlsConfig.ServerName, | ||
Intermediates: x509.NewCertPool(), | ||
} | ||
if asServer { | ||
opts.Roots = tlsConfig.ClientCAs | ||
opts.KeyUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth} | ||
} | ||
if opts.DNSName == "" && len(certs[0].DNSNames) > 0 { | ||
opts.DNSName = certs[0].DNSNames[0] | ||
} | ||
for _, cert := range certs[1:] { | ||
opts.Intermediates.AddCert(cert) | ||
} | ||
_, err := VerifyCertificate(certs[0], opts) | ||
return err | ||
} | ||
} |